网络爬虫技术 - 橙橙Coder
网络爬虫技术
2019-02-01 12:27
橙橙Coder
阅读(130)
评论(0)
编辑
收藏
举报
在java领域有很多spider。其中包括lucene的创始人写的nutch,比较流行的还有Heritrix,J-spider等。不过在其他领域的网络爬虫也有很多,wget[c1] 等。
其他语言写的网络爬虫相比java的要稍微强一些。原因在于java的运行需要很多的内存资源。而爬虫就是一个消耗大量资源的程序。
爬虫就是一个虚拟的浏览器,就是不断的获取URL并请求,获取HTML页面。
淘宝要屏蔽百度的爬虫,只要知道百度爬虫的IP就行了。百度爬虫的IP应该是固定,不可能每天都变。
wget的用法
1、在windows环境中,只要把wget.exe文件拷贝到一个目录下。然后类似java的环境变量一样配置wget的环境变量。[c2] Linux系统下,都自带了wget。[c3] 只是不同的系统有不同的wget版本。
2、启动
-V, –version [c4] 显示wget的版本后退出
-h, –help 打印语法帮助
-b, –background 启动后转入后台执行 v
3、日志和输入文件
-o, –output-file=FILE 把日志写到FILE文件中
-a, –append-output=FILE 把记录追加到FILE文件中
-d, –debug 打印调试输出
-q, –quiet 安静模式(没有输出)
-v, –verbose 冗长模式(这是缺省设置)
-nv, –non-verbose 关掉冗长模式,但不是安静模式
4、下载
-t, –tries=NUMBER 设定最大尝试链接次数(0 表示无限制).
-O –output-document=FILE 把文档写到FILE文件中
-nc, –no-clobber 不要覆盖存在的文件或使用.#前缀
-c, –continue 接着下载没下载完的文件
-N, –timestamping 不要重新下载文件除非比本地文件新
-P, –directory-prefix=PREFIX 将文件保存到目录
-l, –level=NUMBER 最大递归深度 (inf 或 0 代表无穷).
–delete-after 在现在完毕后局部删除文件
-k, –convert-links 转换非相对链接为相对链接
-m, –mirror 等价于 -r -N -l inf -nr. (镜像下载)
5、HTTP设置
–http-user=USER 设定HTTP用户名为 USER.
–http-passwd=PASS 设定http密码为 PASS.
-C, –cache=on/off 允许/不允许服务器端的数据缓存 (一般情况下允许).
-E, –html-extension 将所有text/html文档以.html扩展名保存
6、递归下载中的包含和不包含(accept/reject)
-A, –accept=LIST 逗号分隔的被接受扩展名的列表
-R, –reject=LIST 逗号分隔的不被接受的扩展名的列表
-D, –domains=LIST 空格分隔的被接受域的列表
-X, –exclude-directories=LIST 不被包含目录的列表
-np, –no-parent 不要追溯到父目录
四、例子
wget -P D:\eclipse\ -o E:\wget.log –no-verbose -m -D www.aaa.com –save-headers -N –convert-links -A html,HTML,htm,HTM http://www.aaa.com/[c5]
wget -o ../../log/wget.log –non-verbose -m –D www.cctv.com –save-headers -N –convert-links -R css,js,jpg,jpeg,gif,GIF,ico,exe,pdf,doc,mp3,flv,wmv,flash,png,bmp,GIF,PDF,JPG http://www.cctv.com/
抓取某个招聘网站的信息:
wget -P e:/zhaopin/data -o E:/zhaopin/wget.log –no-verbose -m -D www.zhaopin.com –save-headers -N –convert-links -R jpg,js,jpeg http://www.zhaopin.com/
对于我们现有网络(2M)带宽,尽量不要爬大网站的数据。上次爬了1万多个网页就爬了好久。但是正常的服务器那边是可以的。
只要浏览器能访问的,都能爬。但是一般视频网站的flv是不能爬的。
wget -P E:\xiao\aa\ -o E:\xiao\aa\wget.log –no-verbose -m -D http://www.youbian.com/p110101/ –save-headers -N –convert-links -A html,HTML,htm,HTM http://www.youbian.com/p110101/1.html
wget常用参数如下
GNY Wget ,一个非交谈式的网路抓档工具.
用法: wget [选项]… [URL]…
命令的引数使用长项目与短项目相同.
启动:
-V,
–version显示Wget的版本并且离开.
-h, –help显示这个说明档.
-b,
-background在启动之後跳到背景去.
-e,
-execute=COMMAND执行一个`.wgetrc\’里面的COMMAND指令.
纪录档与输入的档案:
-o,
–output-file=FILE纪录讯息到FILE去.
-a,
-append-output=FILE增加讯息到FILE去.
-d, –debug显示除错的输出.
-q, –quiet安静模式(不输入任何讯息).
-v,
–verbose冗长模式(这是内定值).
-nv,
–non-verbose关闭verboseness,但不是安静模式.
-i,
–input-file=FILE从FILE读取URL .
-F,
–force-html把输入的档案当作HTML.
下载:
-t,
–tries=NUMBER设定重复尝试NUMBER次(0是无限制).
-O
–output-document=FILE把文件写到FILE里.
-nc,
–no-clobber不破坏已经存在的档案.
-c,
–continue重新取得一个已经存在的档案.
–dot-style=STYLE设定取回状况的显示风格.
-N,
–timestamping不取回比本地旧的档案.
-S,
–server-response显示伺服器回应状况.
–spider不下载任何东西.
-T,
–timeout=SECONDS设定读取时超过的时间为SECONDS秒.
-w,
–wait=SECONDS在取回档案时等待SECONDS秒.
-Y,
–proxy=on/off开启或关闭Proxy.
-Q,
–quota=NUMBER设定取回档案的定额限制为NUMBER个.
目录:
-nd
–no-directories不建立目录.
-x,
–force-directories强制进行目录建立的工作.
-nH,
–no-host-directories不建立主机的目录.
-P,
–directory-prefix=PREFIX把档案存到PREFIX/…
–cut-dirs=NUMBER忽略NUMBER个远端的目录元件.
HTTP选项:
–http-user=USER设http使用者为USER.
–http0passwd=PASS设http使用者的密码为PASS.
-C,
–cache=on/off提供/关闭快取伺服器资料(正常情况为提供).
–ignore-length忽略`Content-Length\’标头栏位.
–proxy-user=USER设USER为Proxy使用者名称.
–proxy-passwd=PASS设PASS为Proxy密码.
-s,
–save-headers储存HTTP标头成为档案.
-U,
–user-agent=AGENT使用AGENT取代Wget/VERSION作为识别代号.
FTP选项:
–retr-symlinks取回FTP的象徵连结.
-g,
–glob=on/off turn file name globbing on ot off.
–passive-ftp使用”passive”传输模式.
使用递回方式的取回:
-r,
–recursive像是吸入web的取回–请小心使用!.
-l,
–level=NUMBER递回层次的最大值(0不限制).
–delete-after删除下载完毕的档案.
-k,
–convert-links改变没有关连的连结成为有关连.
-m, –mirror开启适合用来映射的选项.
-nr,
–dont-remove-listing不要移除`.listing\’档.
递回式作业的允许与拒绝选项:
-A,
–accept=LIST允许的扩充项目的列表.
-R,
–reject=LIST拒绝的扩充项目的列表.
-D,
–domains=LIST允许的网域列表.
–exclude-domains=LIST拒绝的网域列表(使用逗号来分隔).
-L,
–relative只跟随关联连结前进.
–follow-ftp跟随HTML文件里面的FTP连结.
-H,
–span-hosts当开始递回时便到外面的主机.
-I, –include-directories=LIST允许的目录列表.
-X,
–exclude-directories=LIST排除的目录列表.
-nh,
–no-host-lookup不透过DNS查寻主机.
-np,
–no-parent不追朔到起源目录.
数据分析(搜索引擎的难点):
将HTML, DOC, PDF文件中的文本抽出来为字符串。
HTML文件的解析:
package com.bjsxt.htmlparser;
import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.List;
import au.id.jericho.lib.html.Element; import au.id.jericho.lib.html.HTMLElements; import au.id.jericho.lib.html.Source; import au.id.jericho.lib.html.StartTag; import au.id.jericho.lib.html.TextExtractor;
public class TestHtmlParser { public static void main(String[] args) { try { new TestHtmlParser().getHtml2(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
public void getHtml() throws InputStream is = this.getClass().getClassLoader().getResource(“a.html”).openStream(); Source Element element = s.findNextElement(0, System.out.println(“标题:” + element.getTextExtractor()); System.out.println(s.getTextExtractor()); System.out.println(“————————“); List list = s.findAllElements(); for (int i = 0; i < list.size(); i++) { Element e = (Element) list.get(i); if ((e.getName().equals(HTMLElements.H3)) && (“select”.equals(e.getAttributeValue(“class”)))) { System.out.print(e.getTextExtractor()); } } }
public void getHtml2() throws InputStream is = this.getClass().getClassLoader().getResource(“a.html”).openStream(); Source //过滤掉符合条件的项 TextExtractor te = new TextExtractor(s) public boolean excludeElement(StartTag return “select”.equalsIgnoreCase(startTag.getAttributeValue(“class”)); } }; System.out.println(s.getTextExtractor()); }
public void getHtml3() throws InputStream is = this.getClass().getClassLoader().getResource(“a.html”).openStream(); Source List list = s.findAllElements(); for (int i = 0; i < list.size(); i++) { Element e = (Element) list.get(i); if ((e.getName().equals(HTMLElements.A))) { String g=e.getAttributeValue(“href”); if(g.lastIndexOf(“.com”)!=-1){ System.out.println(g); } } } } }
|
在项目src下建立a.html文件,内容如下: <!DOCTYPE html <html> <head> <meta http-equiv=“Content-Type” <title>Insert title here</title> <style> .select{color:red;} </style> </head> <body> <p>一个新的段落!</p> <b>大家好!</b> <p>一个new的段落!</p> <h3>h3h3h3!</h3> <h3 class=“select”>h3333!</h3> <a href=“http://www.baidu.com”>百度</a> <a href=“javascript:void(0);”>去哪儿?</a> </body> </html> |
Doc、excel等文件的解析
使用POI (只要涉及到微软的文本格式都会用到它)
解析DOC文件中的文本:
package com.bjsxt.poi;
import java.io.InputStream;
import org.apache.poi.hwpf.HWPFDocument; import org.apache.poi.hwpf.extractor.WordExtractor;
public class Test { static void parseWord() throws InputStream is = Test.class.getClassLoader().getResource(“b.doc”).openStream();
HWPFDocument document=new WordExtractor extractor=new // System.out.println(extractor.getText());
String[] s=extractor.getParagraphText(); //根据段落返回字符串数组 for (int i = 0; i < s.length; i++) { System.out.println(s[i]); } }
public static void main(String[] args) throws Exception parseWord(); }
}
|
static void parseExcel() throws Exception{ // 创建对Excel工作簿文件的引用
} |
PowerPoint文件的解析,自学!
pdf文件的解析(自学):
1, 配置xpdf所在的exe文件的环境变量
2. 在目录下创建一个xpdfrc配置文件
3. 将语言包中的add-to-xpdfrc添加到xpdfrc配置文件中
4. 在命令行执行pdftotext -UTF-8 f:\test.pdf
f:test.text
5. 生成txt文件之后再往程序里边读txt文件就可以了
LUCENE[c6] 概述
一、什么是全文检索与全文检索系统?
1、 扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置。
2、 按字检索和按词检索两种 。
一般都是按词检索。
3、 全文检索系统核心具有索引引擎、查询引擎、文本分析引擎、对外接口等等
索引引擎:创建索引
查询引擎:根据索引查询指定数据
文本分析引擎:比如:分词器
对外接口:方便别的程序调用。
磁盘索引文件:存储索引数据本身
Lucene是什么?
1、lucene是一个高性能的、纯java的、可扩展的信息检索工具库。你可以把它融入到应用程序中以增加索引和搜索功能。
SQL中的like就是一个一个去匹配,效率相当低。正则表达式也是一个一个匹配。对于少量数据没有问题。但是对于海量数据则肯定不行。
数据库中的索引经常用于整数索引,可以大打提高效率。对于字符串就没有必要加索引了,效率太低。
2、a pache软件基金会[4] jakarta项目组的一个成熟,自由,开源的子项目
3、最初的作者是Doug
Cutting
4、使用lucene的实例:apache软件基金会的网站 ,eclipse, IBM的商业 软件Web Sphere
5、刚开始接触lucene的人经常会误认为它是类似于文件搜索程序、Web爬虫或是Web站点搜索引擎的一个现成的应用程序。
Lucene能做什么?
Lucene能够对任意可转换为文本格式的数据进行索引和搜索。
Lucene并不关心数据的来源、格式,甚至文件使用什么自然语言都没有关系,只要可以把它转换成文本。也就是说你可以用Lucene来索引、搜索存放在文件中的诸如以下的数据:远程Web服务器上的网页,本地文件系统中的文档、简单的文本文件、WORD文档、HTML或者PDF格式的文件,或者其他一切能够从中提取文本信息的数据格式。
Lucene优点
- Lucene作为一个全文检索引擎,其具有如下突出的优点:
- (1)索引文件格式独立于应用平台。Lucene定义了一套以8位字节为基础的索引文件格式,使得兼容系统或者不同平台的应用能够共享建立的索引文件。
- (2)在传统全文检索引擎的倒排索引的基础上,实现了分块索引,能够针对新的文件建立小文件索引,提升索引速度。然后通过与原有索引的合并,达到优化的目的。
倒排索引:
分块索引:可以把数据分开。你的系统分布式开发时,非常好。
- (3)优秀的面向对象的系统架构,使得对于Lucene扩展的学习难度降低,方便扩充新功能。
- (4)设计了独立于语言和文件格式的文本分析接口,索引器通过接受Token流完成索引文件的创立,用户扩展新的语言和文件格式,只需要实现文本分析的接口。
- (5)已经默认实现了一套强大的查询引擎,用户无需自己编写代码即使系统可获得强大的查询能力,Lucene的查询实现中默认实现了布尔操作、模糊查询(Fuzzy Search[11])、分组查询等等。
Lucene结构:
建立自己的第一个Lucene工程:
- 增加Jar包:lucene-core2.2jar,(核心包) lucene-analyzers.jar(分析器),
- 建立方法:将所要搜索的文本文件中的内容读到内存中的字符串。
private String getText(File f) {
StringBuffer sBuffer = new StringBuffer();
BufferedReader bReader;
try {
bReader = new BufferedReader(new FileReader(f));
String s = null;
while ((s=bReader.readLine())!=null) {
sBuffer.append(s);
}
} catch (Exception e) {
// TODO Auto-generated
catch block
e.printStackTrace();
}
return sBuffer.toString();
}
- 建立索引:
1、确定存放索引文件的目录。
private static String INDEX_PATH = “d:/lucene/index/”;
2、构建一个新的写索引器。(false:true)
private IndexWriter idx;
public CreateIndex(){
try {
Directory dir = FSDirectory.getDirectory(new File(INDEX_PATH));
idx = new IndexWriter(dir,new
StandardAnalyzer(),true[c7] );
} catch (Exception
e) {
e.printStackTrace();
}
}
3、构建包含多个field的document 文档。
Document:一个要进行索引的单元,任何想要被索引的数据,
都必须转化为Document对象存放。
Document doc1 = new Document();
Document doc2 = new Document();
Field:Document中的一个字段,相当于数据库中的Column ,Field是lucene用的比较多概念一个术语。
doc1.add( new
Field(“name”, “lighter springside
com”,Field.Store.YES,Field.Index.TOKENIZED));
doc2.add( new Field(“name”, “lighter
blog”,Field.Store.YES,Field.Index.TOKENIZED));
4、将Document对象写入索引。
writer.addDocument(doc1);
writer.addDocument(doc2);
5、关闭索引
writer.close();
当IndexWriter执行完addDocument方法后,一定要记得调用自身的close方法来关闭它。只有在调用了close方法后,索引器才会将存放在内存中的所有内容写入磁盘并关闭输出流。
使用luke查看lucene生成的索引文件:
-
1.
下载luke下。执行luke的jar包:
-
2.
打开后,选择path. (选择的是存放索引文件的目录,而不是某个文件),即可查看索引文件中的内容。
lucene的“索引库”你可以抽象成是数据库,Document你可以抽象成是表。那么field可以抽象成表中的各个字段。
类似于JDBC操作。
document对象的作用:
lucene不能直接到某个文件建立索引,lucene只识别document。因此,我们需要讲实体的数据源转化成document对象。
我们现在要对某个网页文件建立索引,以便再将来可以搜索到这个网页。那首先需要讲网页转化成document对象,经分析该网页主要有几个属性可能会用到:title、url、网页的文本内容。那么,我们要建立的document对象应该包含这几个field。
分词器(有很多分词器,可以到google搜索一下):
- 把jar包引入
- 建索引时:writer = new IndexWriter(dir,new IK_CAnalyzer(),true); //中文分词
3. 搜索时最好也用同样的分词器。
自己的第一个搜索程序:
1、实例化IndexSearcher;new方法。
IndexSearcher 类用于搜索IndexWriter类所创建的索引:可以将IndexSearcher类看做一个只读方式打开索引的类。他提供了许多search方法,返回一个Hits对象。
2、实例化QueryParser,并且加入分词器。
3、利用QueryParser得到Query的实例。
4、IndexSearcher的实例可以调用search方法,得到结果集合Hits。然后处理Hits。
Hits 类是一个存放有序搜索结果(Document对象)指针的简单容器,在这里搜索结果是指匹配一个已知查询的一系列文档。出于性能上的考虑,Hits实例不会一次性地从索引中装载所有匹配某个查询的文档,每次只会装载它们中指针。
源代码:
public static void main(String[] args) {
SearchTest sTest = new SearchTest();
try {
IndexSearcher searcher = new IndexSearcher(FSDirectory.getDirectory(CreateIndex.INDEX_PATH));
QueryParser parser = new QueryParser(“fileText”,new
StandardAnalyzer());
Query
query = parser.parse(“java”);
Hits hits = searcher.search(query); //查询到的结果集
for (int i = 0; i < hits.length(); i++) {
Document document = hits.doc(i);
System.out.println(document.get(“fileName”));
}
} catch(Exception e) {
e.printStackTrace();
}
}
解析用户输入的查询表达式QueryParser:
大部分用于搜索的应用程序都需要具备以下两个特征:
能对复杂查询条件进行解析并能访问搜索到的文档。Lucene的search方法需要一个Query对象作为其参数。
QueryParser的使用,QueryParser类中有一个Parse(String query)方法,我们可以对此方法进行地简单的应用。其函数声明如下:
new QueryParser(String field,
Analyzer analyzer)
;
parser.parse(query);
参数field是默认域的名称,这个默认域和表达式中的项相关联。下一个参数是一个Analyzer的实例。
名为query的String对象就是将要被解析的表达式,比如“+cat+dog”。如果对表达式的解析不成功,Lucene就会抛出ParseException异常。
QueryParser把查询表达式转换为Lucene内置的查询类型。如下表,它向我们展示了一些查询表达式的例子以及它们转换后的形式。
查询表达式 |
匹配的文档 |
java |
默认域包含java的文档 |
java junit java OR junit |
默认域包含java和junit中的一个或两个的文档 |
+java +junit java AND[c8] junit |
默认域中同时包含java和junit的文档 |
查询表达式 |
匹配的文档 |
title:ant |
Title域中包含ant的文档 |
title:extreme –subject:sports
title: extreme AND NOT subject:sports |
title域中包含extreme且subject域中不包含sports的文档 |
(agile OR extreme) AND java |
默认域中包含java且包含agile和extreme中的一个或两个的文档 |
title:”junit in action”[c9] |
title域中为junit in action的文档 |
title:”junit action”~5 |
title域中junit和action之间距离小于5的文档 |
java* |
包含由java开头的文档,例如:javaserver等 |
java~ |
包含与java相似的项的文档,例如:lava等 |
date:{1/1/04 |
date域值在01/01/04 和12/31/04之间的文档。可以{}或【】。【】表示闭区间。 值的位数要一样 |