爬虫之概述

来源:互联网 发布:数据库范式详解 编辑:程序博客网 时间:2024/06/02 06:52

爬爬爬~~~


理论基础

爬虫简介

又称网络蜘蛛,可按照制定的规则(网络爬虫算法),进行自动化浏览网络中的信息.
爬虫与搜索引擎: 当用户在搜索引擎上输入关键字时,引擎将对关键字进行处理分析,从后台数据库中的网页中找出相关网页,再按照一定的排名规则呈现给用户.在此过程中,后台网页数据就是通过爬虫获取.
爬虫与数据分析: 爬虫实现自动化网络数据收集,为数据分析提供快速\实时的数据源.
现有爬虫:百度蜘蛛(BaiduSpider) 360Spider SogouSpider 等

爬虫类型

按照实现技术和结构:通用网络爬虫 聚焦网络爬虫 增量式网络爬虫 深层次网络爬虫

通用网络爬虫

又称全网爬虫.爬取目标为全互联网,爬取性能要求极高,因此主要应用于大型搜索引擎.
基本组成: 初始URL集合 URL队列 网页爬行模块 页面分析模块 页面数据库 链接过滤模块
爬行策略: 深度优先爬行策略 广度优先爬行策略

聚焦网络爬虫

也叫主题网络爬虫. 按照预先定义好的主题有选择的进行网络爬去的一种爬虫. 爬取目标为与主题相关的网页, 主要应用于为某一特定的人群提供特定信息的服务
基本组成: 初始URL集合 URL队列 页面爬行模块 页面分析模块 页面数据库 链接过滤模块 内容评价模块 链接评价模块
爬行策略: 基于内容评价 基于链接评价 基于增强学习 基于语境图

增量式网路爬虫

即增量式更新(只更新改变). 只爬取内容发生变化的网页或者新产生的网页.
作用: 一定程度上保证爬去的网页式最新的

深层次网络爬虫

可爬取互联网中深层页面(非静态页面). 爬取深层页面需自动填写对应表单, 其重要部分为表单填写.
表单填写:

  1. 基于领域知识填写,建立一个关键词库并根据语义分析选择对应的关键词进行填写
  2. 基于网页结构分析,根据网页结构分析,并自动填写表单

核心技术理论

实现原理

以聚焦网络爬虫为例, 讲述如何进行网络爬虫
聚焦网络爬虫原理
流程:
1. 依据爬虫需求定义爬取的目标,以及进行相关描述,并爬去初始URL
2. 根据初始URL爬去页面,并获取新的URL
3. 从新的URL中过滤与爬取目标无关的链接,同时将已爬URL地址存放到一个URL列表,用于去重及判断爬取进程
4. 将过滤的链接放入URL列表
5. 从URL列表,根据搜索算法确定URL优先级,并确定下一步要爬取的URL地址
6. 从下一步爬取的URL地址,读取新的URL,然后根据新的URL地址爬去网页,重复上面爬去过程
7. 满足系统设置的停止条件,或者无法获取新的URL地址时,停止爬行
对于聚焦网络爬虫:不同的爬去顺序,可能导致爬虫的执行效率不同

爬行策略

上图中,待爬取的URL列表可能有很多URL地址,如何选择先爬取地址,一般由爬行策略决定.
爬行策略: 深度优先爬行策略 广度优先爬行策略 大站优先策略 反链策略 其他

实例: 假设一个网站, ABCDEFG分别为站点下的网页, 箭头为网页的层次结构
example
深度优先策略: 首先爬去一个网页, 然后将网页的下层链接依次深入爬取完再返回上一层
广度优先策略: 首先爬取同一个层次的网页, 再选择下一个层次的网页爬取
深度策略: A->D->E->B->C->F->G 广度策略: A->B->C->D->E->F->G
大站策略: 按照对应网页所属的站点进行归类,若某个网站网页数量多称为大站, 优先它的网页URL地址
反链策略: 一个网页反链接数为被其他网页指向的次数. 哪个网页反链接数多,就优先爬取
其他: OPIC策略 Partial PageRank策略等

网页更新策略

网站的网页经常会更新,当更新频率和爬取频率不同步时,爬取都是失败的. 因此, 可让不同的网页更新策略也不同, 优先级高的网页更新, 将获得较快的爬取响应
网页更新策略: 用户体验策略 历史数据策略 聚类分析策略
用户体验: 当用户利用搜索引擎进行查询时,往往只关注排名靠前的网页, 因此爬虫会优先更新这些网页
历史数据: 依据一个网页的历史更新数据,利用泊松过程预测网页下一次更新时间,确定爬取时间
聚类分析: 当一个网页为新网页时,上面两种都不适用. 依据类似属性的网页具有类似更新频率, 首先对网页进行聚类, 然后利用同一个类别的所有网页的更新平均值作为这个聚类的爬取频率

网页分析算法

在搜索引擎中,对网页进行成功爬取后, 会对网页进行分析并确定网页的重要性, 在此简单讲述相关分析算法
网页分析算法: 基于用户行为 基于网络拓扑 基于网页内容
基于用户行为: 依据用户对网页的访问行为(访问频率 访问时长 点击率等指标),或者评价对网页综合评价
基于网页拓扑: 依靠网页的链接关系,结构关系,已知网页或者数据对于网页进行分析. 可细分为3种类型: 基于网页粒度算法(PageRank HTIS) 基于网页块粒度 基于网站粒度(SiteRank)
基于网页内容: 基于网页的数据, 文本等网页内容特征, 对网页进行相应评价

身份识别

对网页爬取时, 正规爬虫会告诉网页的网站站长其爬虫身份, 网站的管理员则通过此身份信息对爬虫进行识别
做法: 通过HTTP请求中的User Agent字段告知自己的身份(后面会将具体实现)

实现技术

开发语言: Python Java PHP Node.js C++ Go

  • Python: 爬虫框架丰富, 并且多线程处理能力强,
  • Java: 适合开发大型爬虫项目
  • PHP: 后端处理能力很强, 模块丰富, 并发能力教弱
  • Node.js: 支持高并发与多线程处理
  • C++: 运行速度快, 适合开发大型爬虫项目, 成本较高
  • Go: 高并发能力强

实用工具: metaseeker: 一款实用的网站数据采集程序.

Python爬虫

Urllib爬取网页

Urlllib是一个用于操作URL的模块,爬虫常用到. httplib实现了HTTP协议,是比较底层的实现,一般不直接使用。 urllib, urllib2是对httplib的高层封装,urllib2可以接受一个Request类的实例来设置URL请求的headers,urllib仅可以接受URL。urllib提供urlencode方法用来GET查询字符串的产生,而urllib2没有。所以urllib常和urllib2一起使用. requests是Python第三方库,基于urllib,使用起来比urllib简便.
python3中将Urllib2合并到了Urllib中:http://blog.csdn.net/drdairen/article/details/51149498
python3.x 中

下面以python3进行讲解

快速爬取网页

讲解urllib中快速进行网页爬取函数,流程:
导入相应模块 import urllib.request
request.urlopen(“http://www.baidu.com“)打开网页,放入一个文件变量中
file.read()/file.readline()/file.readlines()读取文件中的内容
print(data)打印出来
保存为本地.html文件格式
解释:
file.read():读取全部文本,放在一个字符串上。
file.readline():读取文本的一行
file.readlines():读取全部文本,放在一个列表

from urllib import requestfile = request.urlopen("http://www.baidu.com")data = file.readline()print(data)fhandle = open(".baidu.html",'wb')fhandle.write(file.read())fhandle1.close()

更直接保存方式:request.urlretrive()
request.urlretrieve(“http://www.baidu.com“,filename=’.baidu2.html’)
urlretrive执行过程会有缓存,一般用request.urlcleanup()清除缓存
file:爬取对象属性
file.info():返回与当前环境有关的信息
file.getcode():获得结果状态
file.geturl():获取当前爬取网页
URL中非标准字符:比如汉字、&或: 解决:urllib.request.quote()进行url中非标准字符编码

request.quote(“http://www.sina.com“)  #output:’http%3A//www.sina.com’

同样,解码用urllib.request.unquote()

request.unquote(“http%3A//www.sina.com”) #output:’http://www.sina.com’

对于汉字,同样可以编码解码:

request.quote(“http://www.sina.字”)  #’http%3A//www.sina.%E5%AD%97’
request.unquote(‘http%3A//www.sina.%E5%AD%97’) #’http://www.sina.字’

以上为简单介绍如何爬取一个网页,并进行简单处理

浏览器模拟

背景:当你爬取一个网页,出现403错误时,因为这些网页为了防止别人恶意采集其信息,所以设置了反爬虫的设置,PS:403 (禁止) 服务器拒绝请求。
解决:设置一些Headers信息,模拟浏览器去访问这些网站,一般需要设置User-Agent信息
目的:在request设置加上User-Agent信息,进行浏览器模。PS:User-Agent信息为浏览器身份,用F12–>network–>header–>request Headers–>User-Agent
两种方式:urllib.request.build_opener()或urllib.request.Request()的add_header()

headers = ('User-Agent',"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36")opener = request.build_opener()  #创建自定义opener对象并赋值给opener对象opener.addheaders = [headers] #opener对象名.addheaders=[头信息],设置对应头信息data = opener.open(url).read()  #opener对象open()打开对应网址,read()读取信息到字符串datahand2 = open('.chromeCSDN2.html','wb')hand2.write(data)hand2.close()print(data)# 利用request.Request中的add_header()req = request.Request(url) #创建一个Request对象# 添加报头信息,格式:Request对象名.add_header(字段名,字段值)req.add_header('User-Agent',"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36")hand3 = open('.chromeCSDN3.html','wb')data2 = request.urlopen(req).read()hand3.write(data2)hand3.close()
超时设置

背景:当访问一个网页,该网页长时间未响应,无法打开网页。
解决:g根据自己需求设置超时的时间值,urllib.request.urlopen(url,timeout=时间值)

from urllib import requesturl ='http://xxxx'for i in range(1,100):    try:        file = request.urlopen(url,timeout=1)        data = file.read()        print(len(data))    except Exception as e:        print("出现异常-->"+str(e))
HTTP协议请求

HTTP协议:进行客户端和服务器端之间的消息传递
HTTP协议分为6种类型,各类型的主要作用:
GET请求:通过URL网址传递消息,可以直接在URL中写上要传递的信息,也可以由表单进行传递。若用表单,表单信息自动转为URL地址中的数据,通过URL地址传递
POST请求:向服务器提交数据,是一种比较主流也安全的数据传递方式,比如登录,常用POST请求发送数据
PUT请求:请求服务器存储一个资源,通常指定存储位置
DELETE请求:请求服务器删除一个资源
HEAD请求:请求获取对应的HTTP报头信息
OPTIONS请求:获得当前URL所支持的请求类型
TRACE请求:主要用于测试或诊断
CONNECT请求
GET请求实例分析
背景:当想在百度查询一个关键词时,手动一般是打开百度首页,输入关键字ggg进行查询,发现URL中有:https://www.baidu.com/s?wd=gggg,截取这段重新打开一个网页,复制点击可以获得该搜索结果。
解释:上面用HTTP的GET请求方法。网页格式:“http://www.baidu.com/s?wd=关键字”

from urllib import requestkeyword = 'ggg'url = 'https://www.baidu.com/s?wd='+keywordreq = request.Request(url)data = request.urlopen(req).read()fhand = open('.HTTPKW.html','wb')fhand.write(data)fhand.close()

说明:按照查询关键字的URL格式构造
编码问题:结合urllib.request.quote()

url2 = 'https://www.baidu.com/s?wd='hanzi = "快乐"key_code = request.quote(hanzi)req = request.Request(url2+key_code)datas = request.urlopen(req).read()hand = open('.httphanzi.html','wb')hand.write(datas)hand.close()

POST请求实例分析
背景:进行注册、登录时,对表单的输入并点击行为,一般用POST请求处理。
登录一般需要用到cookies,此处只用一个简单的表单进行演示。网址:http://www.iqianyue.com/mypost
POST请求实现如下:
设置URL网址
构建表单数据,并使用urllib.parse.urlencode对数据进行编码处理
创建Request对象,参数包括URL地址和要传递的数据
使用add_header()添加信息,模拟浏览器进行爬取
使用urllib.request.urlopen()打开对应的Request对象,完成信息的传递
后续处理:读取网页内存,或存储网页内容
实例:对上地址,查看源码,可知两行输入框属性值分别为”name”和”pass”。字段值用字典格式:{字段名1:字段值1,字段名2:字段值2…}

from urllib import request,parseurls = 'http://www.iqianyue.com/mypost'# 将数据使用urlencode编码处理后,使用encode()设置为utf-8postdata = parse.urlencode({"name":'test1','pass':'123456'}).encode('utf-8')req = request.Request(urls,postdata)# 一般出现403禁止访问,加headerreq.add_header('User-Agent',"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36")data2 = request.urlopen(req).read()hand2 = open('.httppost.html','wb')hand2.write(data2)hand2.close()
代理服务器

背景:当用同一个ip去爬取同一个网站的网页,久了会被该网站服务器屏蔽。那么如何解决这个问题?
思路:瞒天过海,暗度陈仓,不断更换ip去爬取即代理服务器。
代理服务器:当用代理服务器进行爬取,对方网站显示的就是这个代理ip,并不是我们本身的ip
代理服务器地址:http://www.iqianyue.com/proxy ,验证时间比较短的成功概率大。
以下为通过代理服务器爬取网站内容

def use_proxy(proxy_addr,url):    import urllib.request    proxy = urllib.request.ProxyHandler({'http':proxy_addr}) #设置对应的代理服务器的地址    req = urllib.request.build_opener(proxy_addr,urllib.request.HTTPHandler) #自定义opener对象    urllib.request.install_opener(req) #创建全局默认的opener对象,便于后面urlopen(url)时使用安装的opener对象    data = urllib.request.urlopen(url).read().decode('utf-8')    return dataproxy_addr = '202.75.210.45:7777'data = use_proxy(proxy_addr)print(len(data))

一般当一个代理ip失效,换一个代理ip即可,若上代理ip失效,会报不能连接错误,此时可以利用DebugLog进行边运行边打印调试日志。,开启DebugLog:
分别用urllib.request.HTTPHandler()和urllib.request.HTTPSHandler()将debuglevel设置为1
使用urllib.request.build_opener()创建自定义的opner对象,对上中设置的值作为参数
用urllib.request.install_opener()创建全局默认的opener对象,使得urlopen时可以直接使用安装的opener对象
进行后续操作,urlopen()

import urllib.requesturl = 'www.baidu.com'httphd =urllib.request.HTTPHandler(debuglevel=1)httpshd = urllib.request.HTTPSHandler(debuglevel=1)opener = urllib.request.build_opener(httphd,httpshd)urllib.request.install_opener(opener)data = urllib.request.urlopen(url).read()
异常处理

背景:程序执行过程,肯定有各种异常。所以要合理的处理异常,此处讲解如何对一些和URL相关的异常,利用URL异常处理神器——URLError类进行相应的处理。PS:urllib.error模块导入
URLError异常
发生原因:
连接不上服务器
远程URL不存在
无网络
触发了HTTPError

import urllib.errortry:    urllib.request.urlopen("http://www.baidu.com")except urllib.error.URLError as e: #此处原因为触发了HTTPError,因此可以直接将URLError替换为HTTPError    print(e.code) # HTTP的代号:403    print(e.reason) #代号对应的问题:Forbidden

常见的HTTP状态码及含义
200 OK 一切正常
301 Moved Permanently 重定向到新的URL,永久性
302 Found 重定向到临时的URL,非永久性
304 Not Modified 请求的资源未更新
400 Bad Request 非法请求
401 Unauthorized 请求未经授权
403 Forbidden 禁止访问
404 Not Found 没有找到对应页面
500 Internal Server Error 服务器内部出现错误
501 Not Implemented 服务器不支持实现请求所需要的功能
HTTPError子类
是URLError的一个子类,只能处理上面URLError异常的最后一种问题,前面三种不能处理。

但实际中,异常真正原因一般是不知道的,所以改进方法如下:
先让其HTTPError子类进行处理,若无法处理让其用URLError处理。

try:    urllib.request.urlopen("http://www.baidu.com")except urllib.error.HTTPError as e: #若此处不能处理,即原因不是触发了HTTPError,就用下面的机制处理    print(e.code)    print(e.reason)except urllib.error.URLError as e:    print(e.reason)

上面:当子类不能处理时,自动交给父类处理
注意
URLError不能完全替代HTTPError:当异常原因为触发了HTTPError时,e.code会报错,因为不是HTTP原因,就不存在code
解决:对HTTPError和URLError进行整合,利用内置函数hasattr()函数判断后再进行输出

try:    urllib.request.urlopen("http://www.baidu.com")except urllib.error.URLError as e:    if hasattr(e,'code'):        print(e.code)    if hasattr(e,'reason'):        print(e.reason)
正则表达式与Cookie

正则表达式
定义:描述字符串排列的一套规则,python中常见正则表达式函数
re.match():从源字符串的起始位置匹配一个模式,结果为:成功匹配返回匹配结果,不成功则为None;格式:re.match(pattern,string,flag)
re.search():该函数会扫描整个字符串进行对应的匹配,会在全文中进行检索并匹配,即:当字符串开始就不能匹配时,match会返回None,但是search会接着往下找匹配。
re.compile():上面函数中,若字符串有多个结果符合模式,也只会匹配一个结果,利用此解决这个问题。
格式:re.compile(“.python.”)对正则表达式尽心预编译;用findall()返回全部匹配的结果(列表形式)。
re.sub():根据正则表达式实现替换某些字符串的功能,格式:re.sub(pattern,rep,string,max)

正则表达式简单回顾
下面都用re.search()函数
原子类型:
普通字符作为原子:str = ‘http://www.baidu.com’ pattern = ‘bai’ ⇒ match=’bai’
非打印字符作为原子(用于格式控制的符号,比如换行符):str = ‘http://www.baidu.com
http://sina.com’ pattern = ‘\n’ ⇒ match=’\n’
通用字符作为原子(一个原子可以匹配一类字符):有\w、\W、\d、\D、\s、\S等等。例子:str_python = ‘abcdfphp345pythony_py’ pattern = ‘\w\dpython\w’ ==> match=’45pythony’
原子表:定义一组地位平等原子,然后匹配会取该原子表中任意一个原子进行匹配:[xyz]、[^xyz]
实例:对str_python pattern = ‘\w\dpython[xyz]\w’ ⇒ match=’45pythony_’
元字符:具有特殊含义的字符,比如重复N次前面的字符等
. :匹配除换行符意外的任意一个字符,str_python pattern=’.python..’ ⇒ 5pythony_p
^ : 匹配字符串开始位置:str_python pattern=’^abc’ ⇒ abc
:strpythonpattern=py’ ⇒ py
* :匹配0次、1次、多次前面的原子:str_python pattern=’py.*n’==>python
? :匹配0次、或1次前面的原子
+ :匹配1次或多次前面的原子
{n} :匹配前面的原子七号出现n次:str_python2=’abcdddfphp345pythony_py’ pattern=’cd{2}’ ==> cddd
{n,} :匹配前面的原子至少出现n次:str_python2 pattern=’cd{2,}’ ⇒ cdddd
{n,m} :匹配前面的原子至少出现n次,至多出现m次
| :模式选择符:设置多个模式,匹配时从中任意选择一个模式匹配:str_python pattern=’python|php’ ==>php
() :模式选择符:将一些原子组合成一个大原子使用,即小括号括起来会被当做一个整体去使用:
实例:str_python3=’abcdcdcdcdfphp345pythony_py’ pattern=’(cd){1,}’ ⇒ cdcdcdcd

模式修正:可在不改变正则表达式情况下,通过它改变正则表达式的含义,实现一些匹配结果的调整。
常见模式修正符:I(忽略大小写)、M(多行匹配)、L(本地化识别)、U(Unicode字符解析)、S(让.匹配换行符,即.可以匹配任意字符):re.seach(pattern,string,re.I)
贪婪匹配与懒惰匹配
贪婪匹配:str_python pattern=’p.*y’==>php345pythony_py :已经找到一个结尾为y的字符,但是不会停止搜索,继续直到找不到y为止停止搜索
懒惰匹配:str_python pattern=’p.*?y’==>php345py:采用就近匹配原则,让匹配结果更加精确,通过?将贪婪变为懒惰
? 懒惰量词    零个或者一个(可选)
+   占有量词    一个或者多个
贪心量词    零个或者多个
实例:  
   888888
   9999999
  0000000000

输入: .*
它以贪心方式匹配文本中所有字符,所有(8和9)。点号表示任意字符

输入: 9*
它匹配9那行,匹配9零次或者多次
输入: 9.*
它匹配9和0那行,匹配9到后面.的数字。
输入:  9+
它匹配9那行,因为+表示一次或者多次
输入:  9?
它匹配9那行的第一个9(第一次出现了匹配)。
输入:  99?
它匹配第一个9和第二个9。

背景:当涉及登录操作时,经常会使用到Cookie,访问每一个互联网页面都是通过HTTP协议进行,而HTTP协议时一个无状态即无法维持会话之间的状态的协议
解决:将对应的会话信息,如登录成功等信息通过一些方式保存下来,比较常用方式:通过Cookie保存会话信息或通过Session保存会话信息。
Cookie和Seesion
通过Cookie保存会话信息,将会把所有的会话信息保存到客户端,当我们访问同一个网站的其他页面,会从Cookie中读取对应的会话信息,从而判断目前的会话状态。
若通过Seesion保存会话信息,会将对应的会话信息保存在服务器端,但是服务器端会给客户端发sessionID等信息,这些信息一般保存在客户端的Cookie中。用户访问该网站其他网页时,会从Cookie读取这一部分,然后从服务器中的session根据这一部分Cookie信息检索出该客户端的所有会话信息,然后进行控制
Cookiejar实战精析

Python爬虫框架

定义:一些爬虫项目的半成品,编写少量变动的代码部分,按需求调用这些接口。将一些常见的功能代码、业务逻辑等进行封装。
python中常见爬虫框架:
Scrapy框架:高效率爬取web页面并提取关注的结构化数据
Crawley框架:致力于改变人们从互联网提取数据的方式:可将内容轻松存储到关系型数据库,支持非关系型数据库,支持命令行工具,支持Cookie登录访问的网页
Portia框架:一款可视化爬取网页的框架,有本地和网页两个版本,优势为:非编程者可简单使用
newspaper框架:用来提取新闻、文章以及内容分析的python爬虫框架,一个python的库。特点:支持多线程,多语言
python-goose框架:进行文章提取
Fiddler:常见的抓包分析软件,可对http请求进行详细分析及模拟对应的HTTP请求。可捕获HTTPS会话信息,对HTTPS网页进行爬取并解析。还可以用命令快速完成一些功能,具有断点功能,会话查找功能

Python多线程爬虫及实例

图片爬虫

爬虫的浏览器伪装技术
爬虫的定向爬取技术
0 0