Scrapy爬虫
Scrapy
不是一个简单的函数功能库;而是
一个专业的网络爬虫框架
Scrapy 足以支持一般商业服务所需的爬虫能力:持续爬取、商业服务、高可靠性
scrapy库的安装:
pip install scrapy
scrapy -h
Available commands:
bench Run quick benchmark test
commands
fetch Fetch a URL using the Scrapy downloader
genspider Generate new spider using pre-defined templates
runspider Run a self-contained spider (without creating a project)
settings Get settings values
shell Interactive scraping console
startproject Create new project
version Print Scrapy version
view Open URL in browser, as seen by Scrapy
[ more ] More commands available when run from project directory
Unit1、Scrapy爬虫框架
一、Scrapy爬虫框架结构
爬虫框架
爬虫框架是实现爬虫功能的一个软件结构和功能组件集合。是一个半成品,帮助实现专业网络爬虫。 “5+2”结构:
已有实现,不用编写
ENGINE 引擎
控制所有模块之间的数据流根据条件触发事件 SCHEDULER 调度器
对所有爬取请求进行调度管理,排访问顺序
ITEM PIPELINES (出口) 用户编写(也叫配置),对提取的信息进行后处理
以流水线来处理Spider产生的爬取项有一组操作顺序组成,类似流水线,每个操作是一个Item Pipeline类型可能操作包括:清理、检验、查重爬取项的HTML数据、将数据储存到数据库 SPIDERS (入口) 用户编写(也叫配置),提供初始URL链接,并解析所得网页内容,再提供链接
解析Downloader返回的响应(Response)产生爬取项(scraped item)产生额外的爬取请求(Request)
DOWNLOADER 下载页面Downloader Middlewares (中间件)
目的:实施Engine、Scheduler、Downloader之间进行用户可配置的控制功能:修改、丢弃、新增请求或响应(拦截)
Spider Middleware (中间件)
目的:对请求和爬取项再处理功能:修改、丢弃、新增请求或爬取项(拦截)
二、Requests vs. Scrapy
相同点:
都可进行页面请求和爬取,是Python爬虫的两个重要技术路线。两都好用,文档丰富,入门简单。都么有处理js、提交表单、应对验证码等功能(可扩展) 不同:
requests
Scrapy
页面级 网站级 功能库 框架 并发性不足,性能差 并发性好,性能较强(基于异步结构设计,有时太快会被反爬虫发现) 重点在于页面下载 重点在于爬虫框架 定制灵活 一般定制灵活,深度定制困难 上手十分简单 人门稍微难
三、Scrapy爬虫的常用命令
Scrapy命令行 (建立爬虫,运行爬虫)
Scrapy 是为持续运行设计的专业爬虫框架,提供操作的Scrapy命令行。
>scrapy <command> [options] [args]
命令行输入:
scrapy -h
常用命令:
startproject 创建一个新工程 scrapy startproject <name> [dir] genspider 创建一个爬虫 scrapy genspider [options] <name> <domain> settings 获得爬虫配置信息 scrapy settings [options] crawl 运行一个爬虫 scrapy crawl <spider> list 列出工程中所有爬虫 scrapy list shell 启动URL调试命令行 scrapy shell [url]
Scrapy为什么采用命令行?
命令行(而不是图形界面)更容易自动化,适合脚本控制。本质上,Scrapy是给程序员使用的,功能(而不是界面)更重要。
Unit2、Scrapy爬虫基本使用
产生步骤:
建立一个Scrapy爬虫工程
命令行:D:\pycode>
scrapy startproject python123demo
生成工程目录:
Python123demo/------>外层目录
scrapy.cfg ------>部署Scrapy爬虫的配置文件,服务器Python123demo/-->Scrapy框架的用户自定义python代码
__init__.py-->初始化脚本items.py -->Items代码模板(继承类)middlewares.py -->Middlewares代码模板(继承类)pipelines.py -->Pipelines代码模板(继承类)settings.py --->Scrapy爬虫的配置文件spiders/ ----->Spiders代码模板目录(继承类)
__init__.py ----->初始文件,无需修改__pycache__/--->缓存目录,无需修改 在工程中产生一个Scrapy爬虫,产生一个Spider模板
命令行:D:\pycode>
cd python123demo
D:\pycode\python123demo>
scrapy genspider demo python123.io #爬取域名 Created spider 'demo' using template 'basic' in module: python123demo.spiders.demo作用:
生成demo.py 编写产生的Spider模板
修改dome.py文件 运行爬虫,获取网页
start_urls = ['http://python123.io/ws/demo.html']
#等价方法,完整代码部分 :
def start_requests(self):
urls = [
'http://python123.io/ws/demo.html'
]
for url in urls:
yield scrapy.Request(url=url, callback=self.parse)#当Url数量很大时,可以很有效的节省资源
yield关键字
yield <-->生成器
生成器:一个不断产生值的函数包含yield语句的函数是一个生成器生成器每次产生一个值(yield语句),函数被冻结,被唤醒后再产生一个值。
#生成器写法
def gen(n):
for i in range(n):
yield i**2
for i in gen(5):
print(i,' ', end="")
#普通写法
def square(n):
ls = [i**2 for i in range(n)]
return ls
for i in square(5):
print(i,' ', end="")
##当n=1M、10M、100M或更大?生成器的重要优势
为何要使用生成器?
生成器相比一次列出所有内容的优势
更节省储存空间响应更迅速使用更加灵活
Scrapy爬虫的使用步骤:
创建一个工程和Spider模板编写Spider编写Item Pipeline优化配置策略
Scrapy爬虫的数据类型:
1、Request类 (class scrapy.http.Request())
Request对象表示一个HTTP请求 由Spider生成,Downloader执行
属性、方法 .url .method .headers .body .meta .copy() 说明 对应URL 对应请求方法.'GET''POST'
字典类型请求 头
头部自定义
字符串类型请求内容 用户添加的扩展信息,Scrapy内部传递信息 复制该请求
2、Response类 (class scrapy.http.Request())
Request对象表示一个HTTP响应 由Downloader生成,Spider执行
属性和方法:
.url .status .headers .body .flags .request .copy(0 对应URL HTTP状态码,默认200 头部 内容 一组标记 对应Request对象 复制该响应
3、Item类 (class scrapy.item.Item())
Item对象表示一个从HTML页面中提取的信息内容。由Spider生成,由Item Pipeline处理。Item类似字典类型,可以按照字典类型操作。
Scrapy爬虫提取信息的方法:
Beautiful Soup lxml re XPath Selector CSS Selector
Xpath Selector:
举例
##<div id="test1">大家好!</div>
data = response.xpath('//div[@id="test1"]/text()').extract()[0]
##<div id="test3">我左青龙,<span id="tiger">右白虎,<ul>上朱雀,<li>下玄武。</li></ul>老牛在当中,</span>龙头在胸口。<div>
data = response.xpath('//div[@id="test3"]')
info = data.xpath('string(.)').extract()[0]
CSS Selector的基本使用:(由W3C组织维护并规范)
<HTML>.css('a::attr(href)').extract()
a:标签名 href:标签属性
www.w3school.com.cn/cssref/css_selectors.asp (参考链接)
.class .intro 选择 class="intro" 的所有元素。 1
::selection ::selection 选择被用户选取的元素部分。
element p 选择所有 <p> 元素。 1 element,element div,p 选择所有 <div> 元素和所有 <p> 元素。 1 element element div p 选择 <div> 元素内部的所有 <p> 元素。 1
spider中应用举例:
start_urls = ["http://bj.lianjia.com/ershoufang/pg1tt2/"]
def parse(self, response):
# 获取当前页面的房屋列表
#house_lis = response.css('.house-lst .info-panel')
# 把结果输出到文件(在命令行中房屋标题会因为编码原因显示为乱码)
with open("homelink.log", "wb") as f:
## 使用css selector进行操作
#average_price = response.css('
.secondcon.fl li:nth-child(1)').css('
.botline a::text').extract_first()
#f.write("Average Price: " + str(average_price) + "\r\n")
#yesterday_count =
response.css('.secondcon.fl li:last-child').css('.botline strong::text').extract_first()
#f.write("Yesterday Count: " + str(yesterday_count) + "\r\n")
#for house_li in house_lis:
# link = house_li.css('a::attr("href")').extract_first() # 获取房屋的链接地址
# title = house_li.css('a::text').extract_first() # 获取房屋的标题
# price = house_li.css('.price .num::text').extract_first() # 获取房屋的价格
Unit2、实例4,股票数据Scrapy爬虫
要求同实例3
Scrapy爬虫步骤:
创建一个工程和Spider模板
scrapy startproject BaiduStockscd BaiduStocksscrapy genspider stocks baidu.com修改spiders/stocks.py文件 编写Spider
配置stocks.py文件修改对返回页面的处理修改对新增URL爬取请求的处理 编写Item Pipeline
配置pipelines.py文件定义对爬取项(Scrapy Item)的处理类配置Item_Pipelines选项(settings.py文件) 优化配置策略
配置并发连接选项(settings.py文件)
CONCURRENT_REQUESTS Downloader最大并发请求下载数量,默认32CONCURRENT_ITEMS Item Pipeline最大并发ITEM处理数量,默认100CONCURRENT_REQUESTS_PER_DOMAIN 每个目标域名最大并发请求数量,默认8CONCURRENT_REQUESTS_PER_IP 每个目标IP最大并发请求数量,默认0,非0有效 执行程序
scrapy crawl stocks
spider代码:
(stocks.py文件源代码)
# -*- coding: utf-8 -*-
import scrapy
import re
class StocksSpider(scrapy.Spider):
name = "stocks"
start_urls = ['http://quote.eastmoney.com/stocklist.html']
def parse(self, response):
for href in response.css('a::attr(href)').ectract():
try:
stock = re.findall(r'[s][hz]\d{6}', href)[0]
url = 'https://gupiao.baidu.com/stock/' + stock + '.html'
yield scrapy.Request(url, callback=self.parse_stock)
#此处callback 给出处理该Url 所对应的函数
except:
continue
def parse_stock(self, response):
infoDict = {}
stockInfo = response.css('.stock-bets')
name = stockInfo.css('.bets-name').extract()[0]
keyList = stockInfo.css('dt').extract()
valueList = stockInfo.css('dd').extract()
for i in range(len(keyList)):
key = re.findall(r'>.*</dt>', keyList[i])[0][1:-5]
try:
val = re.findall(r'\d+\.?.*</dd>', valueList[i])[0][0:-5]
except:
val = '--'
infoDict.update({'股票名称': re.findall('\s.*\(',name)[0].split()[0]+\
re.findall('\>.*\<', name)[0][1:-1]})
#使用yield,将结果封装成Item类,传给ItemPipeline
yield infoDict
pipelines.py文件源代码:
# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
class BaidustocksPipeline(object):
def process_item(self, item, spider):
return item
class BaidustocksInfoPipeline(object):
#爬虫启动时Pipeline对应的方法
def open_spider(self, spider):
self.f = open('BaiduStockInfo.txt', 'w')
#爬虫关闭时Pipeline对应的方法
def close_spider(self, spider):
self.f.close()
#对每一个Item进行处理时对应的方法:主体函数
def process_item(self, item, spider):
try:
line = str(dict(item)) + '\n'
self.f.write(line)
except:
pass
return item
settings.py文件中被修改的区域:
- # Configure item pipelines
- # See http://scrapy.readthedocs.org/en/latest/topics/item-pipeline.html
- ITEM_PIPELINES = {
- 'BaiduStocks.pipelines.BaidustocksInfoPipeline': 300,
- }
Unit3、扩展
表单提交、爬取周期、入库存储
requests-bs4-re
scrapy + PhantomJS
scrapyd-* https://pypi.python.org
Scrapy 爬虫的应用展望
普通价值:
基于Linux,7*24,稳定输出商业级部署和应用(scrapyd-*)千万规模内URL爬取、内容分析和存储 高阶价值:
基于docker,虚拟化部署中间件扩展,增加调度和监控各种反爬虫对抗技术