scrapy框架(从安装到基本使用)
1、scrapy安装
前提需要安装python,安装scrapy可以直接 pip install scrapy
pip install scrapy安装出现错误一般就是缺少Twisted组件
python大多数库组件以下网站都有:
https://www.lfd.uci.edu/~gohlke/pythonlibs/
安装Twisted:
windows下:进入下载对应的twisted组件,下载后使用cmd进入下载后文件的目录,使用pip install 下载的文件名 安装
linux下:下载Twisted源码,解压并进入安装
Twisted源码地址:https://pypi.org/simple/twisted/
tar -jvxf Twisted-10.1.0.tar.bz2
cd Twisted-10.1.0
python setup.py install
Twisted安装完成后在安装scrapy:pip install scrapy
倘若出现No module named _sqlite3的解决方案:
yum install sqlite-devel
在重新编译python环境
2、scrapy基本结构
scrapy是用纯Python实现的一个为了爬取网站数据、提取结构性数据而编写的应用框架,用途十分广泛。多用于抓取大量静态页面。
框架的力量:用户只要开发几个模块就可以轻松的实现一个爬虫,用来抓取页面内容以及各种图片,非常方便
Scrapy使用了Twisted(其主要对手是Tornado)异步网络框架来处理网络通讯,可以加快我们的下载速度,不用自己去实现异步框架,并且包含了各种中间件接口,可以灵活完成各种需求。
Scrapy Engine(引擎)
:负责Spider、ItemPipeline、Downloader、Schedule中间的通讯,信号,数据传递等。
Scheduler(调度器)
:它负责接收引擎发送过来的Request请求,并按照一定的方式进行整理排列,入队,当引擎需要时,交还给引擎。
Downloader(下载器)
:负责下载Scrapy Engine(引擎)发送的所有Requests请求,并将获取到的response交还给Scrapy Engine(引擎),由引擎交给Spider来处理
Spider(爬虫)
: 它负责处理所有Responses,从中分析提取数据,获取Item字段所需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器)
Item Pipeline(管道)
:它负责处理Spider中获取到的Item,并进行后期处理(详细分析、过滤、存储等)的地方。
Downloader Middlewares(下载中间件)
:你可以当做是一个可以自定义扩展下载功能的组件。
Spider Middlewares(Spider中间件)
:你可以理解为是一个可以自定义扩展和操作引擎和Spider中间通信的功能组件(比如进入Spider的Responses;和从Spider出去的Requests)
详细过程如图
3、scrapy的基本使用:
3.1、 新建项目(scrapy startproject ‘project_name’):新建一个怕从项目
下面介绍一个各个主要文件的作用:
scrapy.cfg:项目的配置文件
mySpider/:项目的Python模块,将会从这里引用代码
myspider/items.py:项目的目标文件
myspider/piplines.py:项目的管道文件
myspider/settingd.py:项目的设置文件
myspider/spiders/:存储怕从代码目录
3.2、明确目标(编写items.py):明确想要抓取的需要存储的数据字段
3.3、制作爬虫(spider/xxspider.py):制作爬虫开始爬取网页
创建爬虫文件:scrapy genspider ‘spider_name’ ‘url’
# -*- coding: utf-8 -*-
import scrapy
from ..items import TenxunItem
class TenxSpider(scrapy.Spider):
name = 'tenx'
allowed_domains = ['tentcent.com']
start_urls = ['https://hr.tencent.com/position.php']
base_url = 'https://hr.tencent.com/'
def parse(self, response):
# 匹配所有的tr标签
tr_list = response.xpath('//table[@class="tablelist"]/tr')
# 匹配下一页地址
next_url = self.base_url+response.xpath('//a[@id="next"]/@href').extract()[0]
yield scrapy.Request(url=next_url,callback=self.parse,dont_filter=True)
for tr in tr_list[1:-1]:
# 匹配数据
items = TenxunItem()
items['position_name'] = tr.xpath('./td[1]/a/text()').extract()
items['position_url'] = '{}{}'.format(self.base_url,tr.xpath('./td[1]/a/@href').extract()[0])
items['position_type'] = tr.xpath('./td[2]/text()').extract()
items['position_num'] = tr.xpath('./td[3]/text()').extract()
items['position_addr'] = tr.xpath('./td[4]/text()').extract()
items['position_time'] = tr.xpath('./td[5]/text()').extract()
# yield items
# 将请求加入到队列
yield scrapy.Request(url=items['position_url'],callback=self.detail_content,meta={'items':items},dont_filter=True)
def detail_content(self,response):
print("*"*30)
items = response.meta.get('items')
content = ''.join(response.xpath('//ul[@class ="squareli"]/li/text()').extract())
items['position_content'] = content
yield items
3.4、存储过程(pipelines.py):设计管道存储数据
设计本地存储为json数据
# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
import json
class TenxunPipeline(object):
def open_spider(self, spider):
self.file = open('tencent.json','a',encoding='UTF-8')
def process_item(self, item, spider):
content = json.dumps(dict(item),ensure_ascii=False)+'\n'
self.file.write(content)
#return item
def close_spider(self, spider):
self.file.close()
还需在myspider/settings.py里面注册管道
# Configure item pipelines
# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
'tenxun.pipelines.TenxunPipeline': 300,
}
3.5、运行scrapy
scrapy list
scrapy crawl spider_name
4、Scrapy shell
Scrapy终端是一个交互终端,我们可以在未启动spider的情况下尝试Scrapy shell调试代码,也可以用来测试XPath或者CSS表达式,查看他们的工作方式,方便我们爬取的网页中提取数据。
进入scrapy shell进行调试,建议安装ipython,该ipython可以提供智能自动完成和彩色输出
启动:scrapy shell
4.1、Selectors选择器(scrapy内置):
selector有四个基本的方法,最常用的还是XPath:
xpath():传入xpath表达式,返回该表达式所对应的所有节点的selector list 列表
extract():序列化该节点为Unicode字符串并返回list
css():传入CSS表达式,返回该表达式所对应的所有节点的selector list列表,语法同BeautifulSoup4
re():根据传入的正则表达式对数据进行提取,返回Unicode字符串list列表
xpath一般是提取结构化数据
5、spider简介
5.1、什么是spider
Spider类定义了如何爬取某个(或者)某些网站,包括了爬取的动作(如:是否跟进链接)以及如何从网页的内容中提取结构化数据(item)。换句话说,spider就是定义爬取的动作及分析某个网页(或者某些网页)并提取数据的地方
5.2、Spider主要的属性和方法
5.2.1、name:
定义spider名字的字符串。具有唯一性
5.2.2、allowed_domains:
包含了spider允许爬取的域名(domain)的列表,可选。如果爬取的网站不在这里面会抓取不到,
其中遇到了"Filtered offsite request to’hr.tencent.com’: <GET https://hr.tencent.com/positi" 这是由于request的地址和allow_domain里面的冲突,从而被过滤掉。可以停用过滤功能。在请求中添加dont_filter=True
5.2.3、strat_urls:
初始URL元祖/列表。当没有特定的URL时,spider姜葱该列表中开始进行爬取
5.2.4、start_requests(self):
该方法必须返回一个可迭代对象(Iterable)。该对象包含了spider用于爬取(默认实现是使用start_urls的url)的第一个request。当spider启动爬取并且未指定start_url时,该方法被调用。如果需要验证登陆是可以重写该方法
5.2.4parse(self,response):
当请求url返回网页没有指定回调函数时,默认的requset对象回调函数。用来处理网页返货的response,以及生成I特么或者Request对象
5.3、怎样编写spider爬取数据
例子:爬取腾讯招聘
# -*- coding: utf-8 -*-
import scrapy
from ..items import TenxunItem
class TenxSpider(scrapy.Spider):
name = 'tenx'
allowed_domains = ['tentcent.com']
start_urls = ['https://hr.tencent.com/position.php']
base_url = 'https://hr.tencent.com/'
def parse(self, response):
# 匹配所有的tr标签
tr_list = response.xpath('//table[@class="tablelist"]/tr')
# 匹配下一页地址
next_url = self.base_url+response.xpath('//a[@id="next"]/@href').extract()[0]
yield scrapy.Request(url=next_url,callback=self.parse,dont_filter=True)
for tr in tr_list[1:-1]:
# 匹配数据
items = TenxunItem()
items['position_name'] = tr.xpath('./td[1]/a/text()').extract()
items['position_url'] = '{}{}'.format(self.base_url,tr.xpath('./td[1]/a/@href').extract()[0])
items['position_type'] = tr.xpath('./td[2]/text()').extract()
items['position_num'] = tr.xpath('./td[3]/text()').extract()
items['position_addr'] = tr.xpath('./td[4]/text()').extract()
items['position_time'] = tr.xpath('./td[5]/text()').extract()
# yield items
# 将请求加入到队列
yield scrapy.Request(url=items['position_url'],callback=self.detail_content,meta={'items':items},dont_filter=True)
def detail_content(self,response):
print("*"*30)
items = response.meta.get('items')
content = ''.join(response.xpath('//ul[@class ="squareli"]/li/text()').extract())
items['position_content'] = content
yield items
5.4、在函数间传递参数item
#meta属性传递参数items
yield scrapy.Request(url=items['position_url'],callback=self.detail_content,meta={'items':items},dont_filter=True)
def jieshou(self,response):
#接收items
items = response.meta.get('items')
6、crawlspider
CrawlSpider使用rules来决定爬虫的爬取规则,并将匹配后的url请求交给引擎。所以正常情况下,CrawlSpider不需要单独手动返回请求了——只需要自己定义好规则后,爬虫自动爬取定义好的规则的内容
在rules中包含一个或多个rule对象,每个rule对爬取网站的动作定义了某种操作,比如提取当前相应内容里的特定链接,是否对提取的连接跟进爬取,对提交的请求设置回调函数等。
如果多个rule匹配了相同的链接,则根据规则在本集合中被定义的顺序,第一个会被使用
规则常用的是正则
6.1、CrawlSpider重要方法有哪些----》Rules
class scrapy.spider.Rule(
Link_extractor,
callback = None,
cb_kwargs = None,
follow = None,
process_links = None,
process_request = None
)
-
Link_extractor: 是一个Link Extractor对象,用于定义需要提取的链接
-
callback:从Link_extractor中每获取到链接时,参数所指定的值作为回调函数,该回调函数接收一个response作为其第一个参数
注意:当编写爬虫规则时,避免使用parse作为回调函数。由于CrawlSpider使用parse方法来实现其逻辑,如果覆盖了parse方法,CrawlSpider将会运行失败
-
follow:是一个布尔(boolean)值,制定了根据该规则从response提取的链接是否需要跟进。如果callback为None,follow默认设置为True,否则默认为False。
-
process_links:指定该spider中那个函数会被调用,从Link_extractor中获取到链接列表时将会调用该函数。该方法主要是用来过滤
-
process_request:指定该spider中那个函数将会被调用,该规则提取到每个request是都会调用该函数(用来过滤request)
6.2、CrawlSpider重要方法有哪些? ----》LinkExtractors
class scrapy.linkextractors.LinkExtractor(
allow = (),
deny = (),
allow_domains = (),
deny_domains = (),
deny_extensions = None,
restrict_xpaths = (),
tags = ('a','area'),
attrs = ('href'),
canonicalize = True,
unique = True,
process_value = None
)
主要参数:
allow:满足括号中“正则表达式”的URL会被提取,如果为空,则全部匹配。
**deny:**满足括号中“正则表达式”的URL一定不提取(优先级高于allow)。
**allow_domains:**会被提取的链接的domains。
**deny_domains:**一定不会被提取链接的domains。
**restrict_xpaths:**使用xpath表达式,和allow共同作用过滤链接。
6.3、使用crawlspider
**创建项目**
scrapy startproject project_name
**创建模版**
scrapy genspider -t crawl spider_name yuming
运行
scrapy crawl spider_name
7、scrapy中间件
下载中间件,代理和IP
8、scrapy对接selenium
为了获取js渲染后的数据,我们在中间件上配置
class AreaMiddleware(object):
def process_request(self,request,spider):
self.driver = webdriver.PhantomJS()
self.driver.get(request.url)
html = self.driver.page_source #js加载之后的源码
self.driver.quit()
return scrapy.http.HtmlResponse(url=request.url, body=html)
设置里面下载中间件里面如下设置
# See https://doc.scrapy.org/en/latest/topics/downloader-middleware.html
DOWNLOADER_MIDDLEWARES = {
#将这里改为这样,这样我们就不仅过下载器,直接调用selenium模拟下载
'area_spider.middlewares.AreaSpiderMiddleware': 543,
}