0.插图一张
任务:利用Scrapy完成网页内容的读取同事筛选出有用(中文+单词+数字)的内容
1.安装配件:1.lxml: lxml是Python语言里和XML以及HTML工作的功能最丰富和最容易使用的库。lxml是为libxml2和libxslt库的一个Python化的绑定。它与众不同的地方是它兼顾了这些库的速度和功能完整性,以及纯Python API的简洁性,大部分与熟知的ElementTree API兼容但比之更优越。
2.zope.interface: python支持多继承,但是不支持接口,zope.inteface是其三方的接口实现库,大量用在twisted中
3.Twisted: 是用Python实现的基于事件驱动的网络引擎框架。
4.OpenSSL(官网上也只有32位的安装包): SSL是Secure Sockets Layer(安全套接层协议)的缩写,可以在Internet上提供秘密性传输。
2.在当前(shift+rmouse)目录下新建项目:
scrapy startproject project_name
1.目录结构如下:
tutorial/
scrapy.cfg 配置文件
tutorial/
__init__.py
items.py 资源项目
pipelines.py 资源目标
settings.py 设置资源
spiders/
__init__.py
... 爬虫
scrapy.cfg:项目的配置文件 (暂时没用到)
tutorial/:项目的Python模块,将会从这里引用代码
tutorial/items.py:项目的items文件 (需要导入item包的Item,Field属性,初始化全局的item字典)
tutorial/pipelines.py:项目的pipelines文件 (设置线程的存储操作等)
tutorial/settings.py:项目的设置文件 (用于设置COOKIES_ENABLED = False ITEM_PIPELINES = ['项目名.pipelines.PipelineName']以及优先级)
tutorial/spiders/:存储爬虫的目录 (爬虫目录,需要导入项目.items中自定义的item类,给item设置有意义的值)
3.明确目标(Item)
在Scrapy中,items是用来加载抓取内容的容器,有点像Python中的Dic,也就是字典,但是提供了一些额外的保护减少错误。
自定义的item可以用scrapy.item.Item类来创建,并且用scrapy.item.Field对象来定义属性(可以理解成类似于ORM的映射关系)。
接下来,我们开始来构建item模型(model)。
首先,我们想要的内容有:
url = Field()
content(title+keywords+descriptions) = Field()
修改tutorial目录下的items.py文件,自定义所需要的item类。
from scrapy.item import Item,Field
class Week1Item(Item):
url = Field()
content = Field()
4.制作爬虫(Spider)
制作爬虫,总体分两步:先爬再取。
也就是说,首先你要获取整个网页的所有内容,然后再取出其中对你有用的部分。
3.1爬
Spider是用户自己编写的类,用来从一个域(或域组)中抓取信息。
他们定义了用于下载的URL列表、跟踪链接的方案、解析网页内容的方式,以此来提取items。
要建立一个Spider,你必须用scrapy.spider.BaseSpider创建一个子类,并确定三个强制的属性:
name:爬虫的识别名称,必须是唯一的,在不同的爬虫中你必须定义不同的名字。
start_urls:爬取的URL列表。爬虫从这里开始抓取数据,所以,第一次下载的数据将会从这些urls开始。其他子URL将会从这些起始URL中继承性生成。
parse():解析的方法,调用的时候传入从每一个URL传回的Response对象作为唯一参数,负责解析并匹配抓取的数据(解析为item),跟踪更多的URL。
下面我们来写第一只爬虫,命名为spider1.py,保存在tutorial\spiders目录下。
import scrapy
import re
from week1.items import Week1Item
class Spider1(scrapy.spiders.Spider):
name = "spider1"
start_urls = []
#从文本(每行一个url)中读取URLs
f = open("H:/spider/week1/week1/urls.txt","r")
for line in f:
start_urls.append(line)
f.close()
def parse(self , response):
#parse使item有实际的意义
item = Week1Item()
#获得本次项目的item
url = response.url + '\t'
# headers = response.headers headers属性返回response的header字典
# headertext = ''
# for key in headers.keys():
# headertext += key+': ['+headers[key]+'] '
sel = response.xpath('/html/head')
title = sel.xpath('title/text()').extract()
Keywords = sel.xpath('meta[@name="Keywords"]/@content').extract()
description = sel.xpath('meta[@name="description"]/@content').extract()
content = ''
p_arv = re.compile(u'[^a-zA-Z0-9\u4e00-\u9fa5]+')
if title!=[]:
content+=re.sub(p_arv,' ',title[0])
if Keywords!=[]:
content+=re.sub(p_arv,' ',Keywords[0])
if description!=[]:
content+=re.sub(p_arv,' ',description[0])
content+='\r\n'
item['url'] = url
item['content'] = content
#给item实际的值
yield item
#将字典和每个爬虫类的parse()的函数名函数绑定
3.2提取Item
Selectors选择器简介
从网页中提取数据有很多方法。Scrapy使用了一种基于 XPath 和 CSS 表达式机制: Scrapy Selectors 。 关于selector和其他提取机制的信息请参考 Selector文档 。
这里给出XPath表达式的例子及对应的含义:
sel = response.xpath('/html/head')
#在(开始为整个文本)当前标签下逐层的到位:/标签名到这个标签
title = sel.xpath('title/text()').extract()
#标签名选择当前位置下的子标签,text()方法获取标签内的文本,extract()返回一个unicode字符串,该字符串为XPath选择器返回的数据
Keywords = sel.xpath('meta[@name="Keywords"]/@content').extract()
#@属性名=“ ”到达标签的属性
为了配合XPath,Scrapy除了提供了 Selector 之外,还提供了方法来避免每次从response中提取数据时生成selector的麻烦。
xpath(): 传入xpath表达式,返回该表达式所对应的所有节点的selector list列表 。
css(): 传入CSS表达式,返回该表达式所对应的所有节点的selector list列表.
extract(): 序列化该节点为unicode字符串并返回list。
re(): 根据传入的正则表达式对数据进行提取,返回unicode字符串list列表。
使用内置的 Scrapy shell 尝试Selector选择器。Scrapy Shell需要您预装好IPython(一个扩展的Python终端)。
您需要进入项目的根目录,执行下列命令来启动shell:
scrapy shell "url"
在此后尝试用xpath()等获得系列网站风格的数据
当shell载入后,您将得到一个包含response数据的本地 response 变量。输入 response.body 将输出response的包体, 输出 response.headers 可以看到response的包头。
更为重要的是,当输入 response.selector 时, 您将获取到一个可以用于查询返回数据的selector(选择器), 以及映射到 response.selector.xpath() 、 response.selector.css() 的 快捷方法(shortcut): response.xpath() 和 response.css() 。
同时,shell根据response提前初始化了变量 sel 。该selector根据response的类型自动选择最合适的分析规则(XML vs HTML)。
实例:
In [1]: sel.xpath('//title')
Out[1]: [<Selector xpath='//title' data=u'<title>Open Directory - Computers: Progr'>]
In [2]: sel.xpath('//title').extract()
Out[2]: [u'<title>Open Directory - Computers: Programming: Languages: Python: Books</title>']
In [3]: sel.xpath('//title/text()')
Out[3]: [<Selector xpath='//title/text()' data=u'Open Directory - Computers: Programming:'>]
In [4]: sel.xpath('//title/text()').extract()
Out[4]: [u'Open Directory - Computers: Programming: Languages: Python: Books']
In [5]: sel.xpath('//title/text()').re('(\w+):')
Out[5]: [u'Computers', u'Programming', u'Languages', u'Python']
之前提到过,每个 .xpath() 调用返回selector组成的list,因此我们可以拼接更多的 .xpath() 来进一步获取某个节点。我们将在下边使用这样的特性:
for sel in response.xpath('//ul/li'):
title = sel.xpath('a/text()').extract()
link = sel.xpath('a/@href').extract()
desc = sel.xpath('text()').extract()
print title, link, desc
3.3使用item
Item 对象是自定义的python字典。 您可以使用标准的字典语法来获取到其每个字段的值。(字段即是我们之前用Field赋值的属性):
一般来说,Spider将会将爬取到的数据以 Item 对象返回。所以为了将爬取的数据返回,我们最终的代码将是:
简单地讲,yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator,调用 fab(5) 不会执行 fab 函数,而是返回一个 iterable 对象!在 for 循环执行时,每次循环都会执行 fab 函数内部的代码,执行到 yield b 时,fab 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。
4.自定义pipelines
pipe是用于定义基于使用item的爬虫后续操作
class Week1Pipeline(object):
def __init__(self):
self.file = open('C://Users//lenovo//Desktop//week1.txt','wb')
def process_item(self, item, spider):
line = item['url']+item['content']
self.file.write(line.encode('utf-8'))
self.file.close()
return item
5.完善settings
BOT_NAME = 'week1'
SPIDER_MODULES = ['week1.spiders']
NEWSPIDER_MODULE = 'week1.spiders'
COOKIES_ENABLED = False 不生成cookie
ITEM_PIPELINES = ['week1.pipelines.Week1Pipeline':优先级]