网络爬虫技术



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
FileNotFoundException, IOException {

       InputStream is = this.getClass().getClassLoader().getResource(“a.html”).openStream();

       Source 
s = new Source(is);

       Element element = s.findNextElement(0,
HTMLElements.TITLE);

       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
FileNotFoundException, IOException {

       InputStream is = this.getClass().getClassLoader().getResource(“a.html”).openStream();

       Source 
s = new Source(is);

//过滤掉符合条件的项

       TextExtractor te = new TextExtractor(s)
{

           public boolean excludeElement(StartTag
startTag) {

              return “select”.equalsIgnoreCase(startTag.getAttributeValue(“class”));

           }

       };

       System.out.println(s.getTextExtractor());

    }  

   

    public void getHtml3() throws
FileNotFoundException, IOException {

       InputStream is = this.getClass().getClassLoader().getResource(“a.html”).openStream();

       Source 
s = new Source(is);

       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
PUBLIC “-//W3C//DTD
HTML 4.01 Transitional//EN” “http://www.w3.org/TR/html4/loose.dtd”>

<html>

<head>

<meta http-equiv=“Content-Type”
content=“text/html; charset=gbk”>

<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
Exception{

       InputStream is = Test.class.getClassLoader().getResource(“b.doc”).openStream();

      

       HWPFDocument document=new
HWPFDocument(is);

       WordExtractor extractor=new
WordExtractor(document);

//     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工作簿文件的引用

         
HSSFWorkbook workbook = new HSSFWorkbook(Test.class.getClassLoader().getResource(“b.xls”).openStream());

 

         
//HSSFSheet sheet =
workbook.getSheet(“第一页”);

         
HSSFSheet sheet = workbook.getSheetAt(0);

         

         
//读取指定索引行的值

         
HSSFRow row = sheet.getRow(1);

         
//读取指定索引格的值

         
HSSFCell a1 = row.getCell((short) 0);

         
HSSFCell a2 = row.getCell((short) 1);

         

         
//读出数据

         
System.out.println(“单元格1: ” +
a1.getRichStringCellValue().getString());

         
System.out.println(“单元格2: ” + a2.getNumericCellValue());

    }

 

 

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工程:

  1. 增加Jar包:lucene-core2.2jar,(核心包)  lucene-analyzers.jar(分析器),
  2. 建立方法:将所要搜索的文本文件中的内容读到内存中的字符串。

    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. 建立索引:

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. 1.      
    下载luke下。执行luke的jar包:

 

  1. 2.      
    打开后,选择path. (选择的是存放索引文件的目录,而不是某个文件),即可查看索引文件中的内容。

 

 

lucene的“索引库”你可以抽象成是数据库,Document你可以抽象成是表。那么field可以抽象成表中的各个字段。

类似于JDBC操作。

 

 

document对象的作用:

       lucene不能直接到某个文件建立索引,lucene只识别document。因此,我们需要讲实体的数据源转化成document对象。

       我们现在要对某个网页文件建立索引,以便再将来可以搜索到这个网页。那首先需要讲网页转化成document对象,经分析该网页主要有几个属性可能会用到:title、url、网页的文本内容。那么,我们要建立的document对象应该包含这几个field。

 

 

 

分词器(有很多分词器,可以到google搜索一下)

  1. 把jar包引入
  2. 建索引时: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
TO 12/31/04}

date域值在01/01/04 和12/31/04之间的文档。可以{}或【】。【】表示闭区间。

值的位数要一样

 

 

 

 


 [c1]C语言写的。

 [c2]到path中增加一个目录即可。或者直接copy到c:/windows下,该目录已经在path中指定了。

必须进入windows目录下?

 [c3]直接敲wget就可以了

 [c4]两种写法都可以。一种简写,一种繁写。

 [c5]最后给爬虫一个入口。让他从这个地方开始爬。

 [c6]是一个人的名字,是lucene作者老婆的名字。

True: [c7]重写和覆盖。

False:追加。

 [c8]这些关键词区分大小写吗?

 [c9]在java中可以用转义字符。这是会把这个字符串作为整体搜索。

版权声明:本文为chenchen-cs原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/chenchen-cs/articles/10345427.html