基本的爬虫架构如图所示,有调度端、URL管理器、网页下载器、网页解析器以及存储价值数据的容器。下面将分别进行讲解。
爬虫调度端其实就是程序入口、开始爬取的URL以及判断是否还有待爬取的URL等功能,想好处理逻辑和流程,这一块没什么问题。
读取一个未爬取的URL,通过下载器下载HTML文档,通过解析器解析出该页面的价值数据以及新的待爬取URL。
URL管理主要是负责管理爬取页面的URL地址管理(存储),包括待爬取的URL和已经爬取的URL。
实现方式有以下几种:
1. 内存:爬取的URL的数量不大时,可直接存在Python内存中,如set(),也省掉去重工作。
2. 数据库:如MySQL等,设置url和is_crawled字段,存储和判断是否已爬取。
3. 缓存数据库:redis,基于内存亦可持久化的日志型、Key-Value数据库。
将网上URL对应的页面下载到本地。
可使用Python官方基础包urllib和urllib2(2.7.X版本),也有强大的第三方包Requests。
这里官方基础包以及足够用。在pyhon3.x中,对原来的urllib做了很多的修改。将Request,error,urllib2等都归一到了urllib中。
#urllib
url = 'http://www.seu.edu.cn'
web = urllib.urlopen(url)#为指定的URL创建一个类似文件的对象。
#此时web与文件类似,可以使用read(),readline(),readlines(),fileno(),close()等方法
web.info()#返回一个httplib.HTTPMessage对象,远程服务器返回的头信息
web.getcode()#返回HTTP状态码,200表示访问成功
web.geturl()#返回请求的URL
values={'name':'sun','age':25}
data = urllib.urlencode(values)#将两个元素元组或字典的序列编码到一个URL查询字符串中。
web2 = urllib.urlopen(url,data)#为指定的URL创建一个类似文件的对象,带data
#urllib2
url = 'http://www.seu.edu.cn'
request = urllib2.Request(url)
request.add_header('User-agent','Mozilla/5.0')#添加头部信息
response = urllib2.urlopen(request)#返回一个文件类对象,可以用read()等方法
response.info()
request.get_header('User-agent')
urllib 和urllib2都是接受URL请求的相关模块,但是提供了不同的功能。两个最显著的不同如下:
urllib2可以接受一个Request类的实例来设置URL请求的headers,urllib仅可以接受URL。这意味着,你不可以伪装你的User Agent字符串等。
urllib提供urlencode方法用来GET查询字符串的产生,而urllib2没有,这是为何urllib常和urllib2一起使用的原因。
#urllib和urllib2配合使用
import urllib,urllib2
url = 'http://www.seu.edu.cn'
usr_agent = 'Mozilla/4.0(compatible;MSIE5.5;windows NT)'
values = {'name': 'sun', 'age': 25}
headers = {'User-agent': usr_agent}
data =urllib.urlencode(values)
#request.add_data(data)
#request.add_header(k,v)#也可以再添加
request = urllib2.Request(url, data,headers)
response = urllib2.urlopen(request)
有多种方式可以进行网页解析,如:
正则表达式——模糊匹配,直接找出html文档里想要的字符串
Beautiful Soup、lxml等结构化解析——DOM树
from bs4 import BeautifulSoup
from lxml import etree
import re
#使用BeautifulSoup
read = response.read()
soup = BeautifulSoup(read, #HTML文档
'html.parser', #HTML解析器
from_encoding='utf-8' #编码
)
#可以传入正则表达式匹配,string='..'节点内容
list = soup.find_all('a',href=re.compile(r'^http://news\.xinhuanet\.com/.*'))
for link in list:
#节点名称,节点对应的属性值,node.string节点内容
#若属性为class写成class_
print link.name, link['href'], link.get_text()
#使用lxml
selector = etree.HTML(read)
content = selector.xpath('//ul/li')#找到所有ul节点的子节点li
for site in content:
#找到li节点下a节点属性为target="_blank"的节点内容
for title in site.xpath('a[@target="_blank"]/text()'):
print title,
#找到li节点下a节点属性为target="_blank"的节点href属性值
for link in site.xpath('a[@target="_blank"]/@href'):
print link,
print
有问题欢迎指正,谢谢!
后面会再写出一个爬取的实例。