前几天公司要求我将数据库里的pages表里的title和sumarry列填充一下,这个表已经通过crawler填充了页面的url。所以我只要获取每个页面的url然后取得这个页面的内容就可以很容易取得某个字段,但是当中发生了一些问题。
1.获取页面的代码:
要用到以下类必须在pom.xml里加入下面的依赖:
<dependency>
<groupId>nekohtml</groupId>
<artifactId>nekohtml</artifactId>
<version>0.9.5</version>
</dependency>
<dependency>
<artifactId>commons-httpclient</artifactId>
<groupId>commons-httpclient</groupId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>com.ibm.icu</groupId>
<artifactId>icu4j</artifactId>
<version>3.8</version>
</dependency>
判断页面字符集的方法:
/**
* Determine the page encoding from the binary stream
* @param is The source on which the process is executed.
* @return
*/
public String getCharset(InputStream is){
CharsetDetector detector;
CharsetMatch match;
detector = new CharsetDetector();
try {
BufferedInputStream inputStream = new BufferedInputStream(is);
detector.setText(inputStream);
} catch (Exception e1) {
e1.printStackTrace();
}
detector.enableInputFilter(true);
match = detector.detect();
String charset = match.getName();
return charset;
}
CharsetDetector 类是分析页面字符给出最可能的结果,比如百度百科的页面编码都是”gb2312"的,但是得出的结果为:GB18030,也即前者编码的超集。
获取页面内容代码:
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
public static byte[] downloadContent(String url) {
byte[] buffer = new byte[1024 * 100];
HttpClient httpClient = new HttpClient();
GetMethod getMethod = new GetMethod(url);
try {
int rt = httpClient.executeMethod(getMethod);
if (rt == HttpStatus.SC_OK) {
// int count = -1;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
InputStream responseBodyAsStream = getMethod.getResponseBodyAsStream();
while((count = responseBodyAsStream.read(buffer, 0, buffer.length)) > -1) {
baos.write(buffer, 0, count);
}
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
return baos.toByteArray();
}else {
return null;
}
} catch (Exception e) {
logger.error("error occur, while download page at the location of: " + url, e);
return null;
}finally {
getMethod.releaseConnection();
}
}
再看看ByteArrayOutputStream的API:
ByteArrayOutputStream
This class implements an output stream in which the data is written into a byte array. The buffer automatically grows as data is written to it. The data can be retrieved using toByteArray() and toString().
Closing a ByteArrayOutputStream has no effect. The methods in this class can be called after the stream has been closed without generating an IOException.
引用
The buffer automatically grows as data is written to it.
由于该类的buffer会自动增长,所以如果网页的大小超过预设的buffer大小的话它也能过这个特性来存放数据(除了网页的内容大的超过所剩内存大小,这时候就会出现OOM异常了)
一开始是直接返回一个InputStream,即getMethod.getResponseBodyAsStream();但是在另外一个类读这个stream的时候会报“attempted to read a closed stream",猜想应该是另外一个引用这个InputStream时被调用方法堆栈的对这个流的reference已经释放,所以才会抛出这个错误。因为这个原因,后来便直接在该方法中读出页面内容然后返回一个缓冲引用。
在返回缓冲的时候出了一个问题困扰了我好久。因为网页的大小会相差较大,所以100K的缓存有时候能一次性容纳一个网页,有时候必须要读好几次缓存才能获取所有页面的内容。一开始是直接return buffer,所以遇到小的页面是,所得的结果完全正确,而遇到大的页面超出缓存的大小时,这时候buffer的内容总是最后一次读取的大小,而前面读取的内容则被覆盖了,因此经常出现取不到title的情况。而用以上方法获取字符集的时候,也会因为数据不全而出现时对时错的情况。下次在获取诸如不确定大小数据的时候,一定要小心这个问题。
后来发现有一个类似的帖子:http://dengyin2000.iteye.com/blog/47417。
还想问一个问题,在获取description的时候,本人的代码是通过正则表达式来作的,如下:
public String getDescription(String page){
String description = null;
Pattern pattern = Pattern.compile("(<meta)(.*)name *= *[\"\'] *description *[\"\'](.*)(/>)", Pattern.CASE_INSENSITIVE );
Matcher matcher = pattern.matcher(page);
// boolean found = false;//flag indicating whether the page has a description.
String resultStr = null;
while(matcher.find()){
resultStr = matcher.group();
Pattern patternDesc = Pattern.compile("(content *= *[\"\'])(.*)([\"\'])", Pattern.CASE_INSENSITIVE);
Matcher matcherDesc = patternDesc.matcher(resultStr);
while(matcherDesc.find()){
description = matcherDesc.group(2);
}
// found = true;
}
//If no description found, then set title as its description
/*if(!found){
description = title;
}*/
return description;
}
在html中,一个tag里的attribute位置和个数不确定。在获取description时,通过查找是否有name=”description“的<meta/>字符串然。找到后再来查找content的attribute。这里用了两次正则表达式查找。不知道各位有没有更好的方法一个正则表达式就可以查出来的呢?
分享到:
相关推荐
获取页面title,获取页面url,获取页面头部信息
补充知识:vue 每个页面动态切换title keywords description (seo的设置) 最近接触到需要使用到Seo,要求每个页面拥有不同的title,keywords,description !!!在这里先添加一步: html文件添加 <meta data-n-...
主要介绍了js获取页面description的方法,涉及javascript操作页面元素的相关技巧,需要的朋友可以参考下
批量获取网站title脚本
根据url获取到url的title
用于建设网站效果;title滚动,页面title滚动
通过PHP获取页面title内容的实战演示: 范例代码: 复制代码 代码如下: <?php /* 功能: 取得 URL 页面上的 <title> 内容 参数:$_POST[‘url’] */ // 设置最长执行的秒数 ini_set (...
Test404轻量Title获取器 v2.0Test404轻量Title获取器 v2.0 (去除更新优化版) 这款工具的最大亮点在于扫描的速度非常之快,相信大家会喜欢的。
子页面: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <style type="text/css"> </style> </head> <body> [removed] var val=window.parent....
在React搭建的SPA项目中页面的title是直接写在入口index.html中,当路由在切换不用页面时,title是不会动态变化的。那么怎么让title随着路由的切换动态变化呢? 1.在定义路由时增加title属性。 { path: /...
title 获取当前页面的title; 将以上方法按顺序练习一遍,效果如GIF: from selenium import webdriver from time import sleep sleep(2) driver = webdriver.Chrome() driver.get(https://www.baidu.com/) # ...
抓取雅虎网页源码,通过对字符串的解析获取url以及title
本文实例讲述了JavaScript获取当前网页标题(title)的方法。分享给大家供大家参考。具体如下: JS中的document.title可以获取当前网页的标题 <!DOCTYPE html> <html> <head> <title>jb51.net...
网站网页标题title获取工具,快速批量导入网址,快速获取网址标题title,方便快捷进行统计分析处理。
VC获取网页标题.zip
可以轻松获取对方的head头部seo信息
css模拟title和alt的提示效果,可以查看淘宝网里的产品展示页面,用于显示产品的规格和相关信息.
通过文章标题获取页面信息,如果多个文章标题一致返回id最小的文章信息。【使用】 【参数】 $page_title (string) (必须) 文章标题 Default: None $output (string) (optional) 返回值类型. OBJECT, ARRAY_N, or ...
获取h5页面的携带的title中是很简单的,下面这篇文章主要给大家介绍了关于Android开发笔记之如何正确获取WebView的网页Title的相关资料,文中通过示例代码介绍的非常详细,需要的朋友们下面来一起看看吧