各位大哥,小弟在这求救了……首先我说下我自己写的网络爬虫思想:1.首先,得到一个URL,截取重要字段如:“http://www.163.com” 我截取:“163.com”部分。2.其次,根据第1个步骤得到的URL,系统分配一个线程给它,然后根据URL去攫取有用的网址,进一步去爬取网络信息。3.最后,根据攫取的信息,分析内容,截取重要内容保存数据库中。问题如下:请问上面的思想有什么问题没有呢?各位大哥,在第2步中,每一个URL都是分配一个线程,然后在一个线程下,又发现新的URL,继续用本线程去爬取,可有会问题?当线程启动多了,发现如果只是启动一个线程会爬取很多的信息,如果是启动多个线程,发现爬取的信息就少了,请部这个是什么问题呢?如何解决当前各大网站字符编码的问题?因为当前的各大网站启用的编码不标准,没有通用的,有的使用UTF-8,有的使用GBK2312,等等。如何解决爬行数据乱码问题?在网站的后台,如何停止正在爬行数据的线程?
下面是图片截图:
下面是图片截图:
你的cpu会爆掉,可以采用队列的方式处理,发现一个连接 把连接加入队列里面去...然后开固定数目的线程,去队列中取数据...
如何解决当前各大网站字符编码的问题?因为当前的各大网站启用的编码不标准,没有通用的,有的使用UTF-8,有的使用GBK2312,等等。如何解决爬行数据乱码问题?
有一个工具 可以 自动分析页面的编码,我忘记了,是根据页面流来处理的,还可以分析页面上是否有"gbk""utf-8""gb2312"等字样来确认
另外涉及到一个线程排重的问题,我用的B-树的数据结构,而berkely db嵌入式数据库也用的这个数据结构,所以我就直接用了他,性能跟自己写的纯粹为排重设计的红黑树或者B-树分毫不差。当年我做了一个,还有架构图。主要的关键点:URL队列,排重,线程池。
另外编码问题,我的方式是直接下载下来,如果HTTP头里有编码信息就直接用,如果没有,就先按照任意编码解码,也许里面中文会是乱码,但是<mata encode="gb2312"/>这一类的html里的编码信息是英文和数字,是不会乱码的,你用htmlparser一类的解析器把它解析出来,再重新解码一次就能得到正确的String了
HttpURLConnection http;
....略...
http = (HttpURLConnection) url.openConnection();
....略... String charsets = "GBK";
Map m = http.getHeaderFields();
String contentType = m.get("Content-Type").toString().toLowerCase();
if(contentType.indexOf("utf")>-1){
charsets = "UTF-8";
}InputStream httpInputStream = http.getInputStream();
BufferedReader httpBufferedReader = new BufferedReader(new InputStreamReader(httpInputStream,charsets));....略...在网站的后台,如何停止正在爬行数据的线程?
强制终止线程[/color]
第一件事情,就是从表中取一条状态位为 0 记录,然后下载内容到本地,然后把这条网址的状态位标志为1。(如果表为空,你就相当于{http://www.163.com,0})
第二件事情就是分析一下刚下载的内容,用正则也好,别的方法也好,分析出来里面所有有用的 URL ,然后保存到任务表中(状态位为0),当然这个表里面的网址是不能重复的,你要保存之前先查一下里面有没有。
所以只要一个循环让程序去做这两件事就可以了 ,循环中不断去检测一个标志,如果标志为停止则停止循环。如下,不是标准语言:
int runFlag = 1;while (runFlag) { int runFlag = file_get_contents("./run.lock"); // (从文件中读取一个数据,这个数据就是停止信号。当然可以是保存在文件中,也可以是数据库中,设置 内存中,memcache 中,总之能读到的地方,你可以设置这个数值为 false 来终止程序) url = readFromDB(); //从数据库中取一条没有下载的 URL contents = downloadFromUrl(url); // 下载内容 if (getCharsetOfContents(contents) == "GBK") { // 检查下编码是不是你要的编码,不是,转
contents = iconv("GKB", "UTF-8", contents);
} saveContents(contents); // 保存内容 urlsFromContents = preg_match_all(contents); // 从下载内容中取所有的 URL, foreach (urlsFromContents as k => v) { // 入库 URL
if (checkExistsUrl($v)) {
insertToDB($v);
}
}
}
对于编码问题,可以先分析meta标签来获得,然后在用获得的字符集去转换网页文件。网页文件解析可以使用HTML Parser库。
推荐使用jsoup 可以直接从网页抓取任意标签内的信息
有些网站的编码很乱 例如 天涯 强力BS
编码问题可以用cpdetector。。(名字差不多吧)这个包,但用了它效率肯定不好。建议自己分析,没必要每个网页都分析正确无误,大部分正确就可以了。
用不用线程池无关紧要。开固定数目的线程死循环抓取,不比线程池效率差,还可以省掉管理线程池的开销。
注意线程间的数据同步。
设计一个URL过滤器,可以实现许多实用的功能。
BerkeyDB数据库不错.但如果你要抓取的URL在亿级以上的话,还是有效率问题。
html-parser这东东就不必用了。非要用的话,可以自己把里面的关键部分拿出来,自己写个处理类。
可以考虑异步IO的方式去获取数据,(JAVA-NIO),可能会有一点效率的提升,但需要你学会用。(新的HttpClient里面似乎有这功能)。结束爬行?结束线程就可以了 。怎么结束线程就不是爬虫的问题,是java的问题了。
请注意使用volatile关键字。
编码问题可以分析<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
这个可以用htmlparser来解决
对于字符编码问题,你可以通过的到返回html,从头部拿到起字符编码,当然不是所有的都可以拿到。
想做爬虫,你可以看看httpclient,这个很好用的