讨论:java搜索引擎之网络爬虫研究 思想
各位大哥,小弟在这求救了……
首先我说下我自己写的网络爬虫思想:
1.首先,得到一个URL,截取重要字段如:“http://www.163.com” 我截取:“163.com”部分。
2.其次,根据第1个步骤得到的URL,系统分配一个线程给它,然后根据URL去攫取有用的网址,进一步去爬取网络信息。
3.最后,根据攫取的信息,分析内容,截取重要内容保存数据库中。
问题如下:
请问上面的思想有什么问题没有呢?各位大哥,在第2步中,每一个URL都是分配一个线程,然后在一个线程下,又发现新的URL,继续用本线程去爬取,可有会问题?
当线程启动多了,发现如果只是启动一个线程会爬取很多的信息,如果是启动多个线程,发现爬取的信息就少了,请部这个是什么问题呢?
如何解决当前各大网站字符编码的问题?因为当前的各大网站启用的编码不标准,没有通用的,有的使用UTF-8,有的使用GBK2312,等等。如何解决爬行数据乱码问题?
在网站的后台,如何停止正在爬行数据的线程?
下面是图片截图:
[解决办法]
请问上面的思想有什么问题没有呢?各位大哥,在第2步中,每一个URL都是分配一个线程,然后在一个线程下,又发现新的URL,继续用本线程去爬取,可有会问题?
你的cpu会爆掉,可以采用队列的方式处理,发现一个连接 把连接加入队列里面去...然后开固定数目的线程,去队列中取数据...
如何解决当前各大网站字符编码的问题?因为当前的各大网站启用的编码不标准,没有通用的,有的使用UTF-8,有的使用GBK2312,等等。如何解决爬行数据乱码问题?
有一个工具 可以 自动分析页面的编码,我忘记了,是根据页面流来处理的,还可以分析页面上是否有"gbk""utf-8""gb2312"等字样来确认
[解决办法]
使用html-parser几乎最有效的,使用其中的工具类分析<meta>头部信息得到相关编码。然后分析<a>标签包含链接(可能有多个),随后进行递归就可以。具体html-parser使用方法还有有很多技巧:http://htmlparser.sourceforge.net
[解决办法]
我告诉你我的方法,其实最简单的方法是不要采取一个URL一个线程,而是把所有解析出来的URL都放到一个队列里。而固定数量的工作线程就负责从这个队列里不停取URL并下载解析把新的URL再次放进去。
另外涉及到一个线程排重的问题,我用的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));....略...
[解决办法]
........................................然后根据URL去攫取有用的网址,进一步去爬取网络信息。
3.最后,根据攫取的信息,分析内容,截取重要内容...........................................
如何"攫取",用的什么算法,锚文本是如何分析的,模式分类算法有没有?
另外网络拓扑的概念呢?什么样的URL重要,什么样的不重要,链进链出的URL怎么分类统计的.....
--------------------
爬虫....
[解决办法]
首先要理清思路,理清了也简单了。
要有一个任务表来辅助实现队列功能,她记录记下几点内容:
采集的网址(唯一,内容不能重复),状态位(1为已经采集内容,0为没有采集内容,默认为 0)
有了这个小表,以后就简单了,程序只来做两件事情。
第一件事情,就是从表中取一条状态位为 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);
}
}
}
[解决办法]
支持一楼的,补充一点,建议看看Heretrix,这个对你有帮助的,Heretrix就死使用队列加线程池的。
对于编码问题,可以先分析meta标签来获得,然后在用获得的字符集去转换网页文件。网页文件解析可以使用HTML Parser库。