http://scrapy-chs.readthedocs.io/zh_CN/1.0/intro/overview.html
scrapy 使用Twisted 这个异步网络库来处理网络通信,使用python写的爬虫框架。
scrapy的构造
Scrapy引擎(Engine): 负责控制数据流在系统的所有组件中流动,并在相应的动作发生时出发事件。
Scheduler 调度器: 从引擎接收Request并将它们入队,以便之后引擎请求request是提供给引擎。
Donwnloader 下载器: 负责获取页面数据并提供给引擎,而后提供给Spider,或额外跟进的URL的类。每个Spider负责处理一个(或一些)特定网站。
Item Pipeline 数据传递管道: 负责处理被Spider提出出来的item。典型的处理有清理验证及持久化(例存储到数据库中)。
Downloader middlewares 下载器中间件: 是一个在引擎和下载器中间的特定钩子(specific hook ),处理Downloader传递给引擎的Response。中间件通过插入自定义代码,扩展Scrapy的功能
Spider middlewares Spider中间件: 是一个在引擎和Spider中间的特定钩子,处理spider的输入(response)和输出(Item及request )
Spider : 包含初始的URL,解析相应的response,提取目标items和requests.
scrapy中的数据流程
1) 引擎打开一个网站,找到该网站的Spider并向该Spider请求第一个要爬取的URL。
2) 引擎从spider中获取初始要爬取的URL ,并传给调度器(sheduler)处理验证筛选URL的规则。
3) 引擎向调度器请求下一个要爬取的URL
4) 调度器返回下一个要爬取的URL给引擎,引擎将URL通过下载中间件(请求request 方向)转发给下载器
5) 下载器下载完页面,返回response,通过下载中间件(返回response方向)发送给引擎
6) 引擎从下载器中接收到Response并通过spider中间件(输入方向)发送给spider处理
7)spider处理response并返回提出的item及新的request给引擎
8)引擎 将spider返回的item和request分别发给item pipeline 和调度器sheduler 处理
9)重复第3步,直到调度器中没有更多的request,引擎关闭网站。
在命令行中移动到想创建项目的目录下,输入指令 scrapy startproject cnblogSpider 就可创建一个名为cnblogSpider的项目。创建后会出现如下目录文件
scrapy.cfg:项目部署文件
cnblogSpiders/:该项目的Python模块,之后可在此加入代码
cnblogSpiders/settings.py: 项目的配置文件
cnblogSpider/spiders/:放置spider代码的目录
创建spider类,将脚本放在cnblogSpider/spiders/目录下,命名为cnblogs_spider.py
该类需要继承scrapy.Spider,并定义三个属性 name(爬虫的名字,具有唯一性),start_urls(初始URL列表),parse(response)(解析传入的response,返回提取的目标数据)。
import scrapy
from cnblogSpider.items import CnblogspiderItem
from scrapy.selector import Selector
class CnblogsSpider(scrapy.Spider):
name="cnblogs"
allowed_domains=["cnblogs.com"]
start_urls=["http://www.cnblogs.com/qiyeboy/default.html?page=1"]
def parse(self,response):
papers=response.xpath('//*[@id="mainContent"]/div/div[@class="day"]')
print('*'*15,len(papers),'-'*30)
mm=0
for paper in papers :
mm =mm + 1
print(mm)
url = paper.xpath(".//*[@class='postTitle']/a/@href").extract()[0]
title=paper.xpath(".//*[@class='postTitle']/a/text()").extract()[0]
time=paper.xpath(".//*[@class='dayTitle']/a/text()").extract()[0]
content=paper.xpath(".//*[@class='postCon']/div/text()").extract()[0]
item = CnblogspiderItem(url=url,title=title,time=time,content=content)
yield item
next_page=Selector(response).re(u'<a href="(S*)">下一页</a>')
if next_page:
yield scrapy.Request(url=next_page[0],callback=self.parse)
选择器Selector ,scrapy自有的数据提取机制构建与lxml库之上,通过特定的xpath,css表达式选择html文件中的某个部分。
创建一个selector对象,a=Selector(response),就可以对其调用方法a.xpath(query),a.css(query),a.extract()(序列化该节点为Unicode字符串并返回list列表),a.re(regex)(regex可以是原始正则表达式或已被re.compile()编译的正则对象,返回Unicode字符串列表) 。 response可直接调用xpath(),css()方法。
在命令行中输入 scrapy
这时在命令行 进入到项目的根目录cnblogSpider/下 输入 scrapy crawl cnblogs ,就可以看到解析的数据了。
通过yield 返回item ,将parse方法打造成一个生成器。
next_page 使页面翻页,获取下一页的URL列表
定义Item cnblogSpider/items.py
import scrapy
class CnblogspiderItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
url=scrapy.Field()
time=scrapy.Field()
title=scrapy.Field()
content = scrapy.Field()
这个类需要继承scrapy.Item,CnblogspiderItem的类实例对象,对其里面的键值对,具有和字典一样的使用方式
创建一个CnblogspiderItem对象,a=CnblogspiderItem(title='python爬虫',content='爬虫开发')
print(a.items(),a.keys(),a['title'],a.get('content','ahsdkahdkabdkabnka'))
print(dict(a))
输出:
ItemsView({'content': '爬虫开发', 'title': 'python爬虫'}) dict_keys(['content', 'title']) python爬虫 爬虫开发
{'content': '爬虫开发', 'title': 'python爬虫'}
构建Item Pipeline cnblogSpider/pipeline.py
实现数据的的持久化存储。一般具有下面几种功能:清理HTML数据,验证爬取数据的合法性(检查item是否包含某些字段),查重并去重,将爬取结果保存到文件或数据库中。
import json
from scrapy.exceptions import DropItem
class CnblogspiderPipeline(object):
def __init__(self):
self.file=open('papers.json','wb')
def process_item(self, item, spider):
if item['title']:
line=json.dumps(dict(item))+' '
self.file.write(line.encode())
return item
else:
raise DropItem('Missing title in %s' % item)
此段代码主要是检查了item中是否包含title字段,有就写入json文件,没有就抛出错误。
创建完Item Pipeline后还需在配置文件cnblogSpider/settings.py里将item pipeline的类添加到ITEM_PIPELINES变量中。
ITEM_PIPELINES={'cnblogSpider.pipelines.CnblogspiderPipeline':300,}
ITEM_PIPELINES变量中可配置多个Item Pipeline组件,分配给每个类的整型值确定了它们的运行顺序,item按数字从小到大的
顺序通过 Item Pipeline.通常数字的范围是0~1000.
从程序内启动spider:
在cnblogs_spider.py 中添加如下代码:
if __name__=='__main__':
process=CrawlerProcess({
'USER_AGENT':'Mozilla/4.0 (compatible;MSIE 7.0; Windows NT 5.1)'
})
process.crawl(CnblogsSpider)
process.start()
'''
if __name__=='__main__':
configure_logging({'LOG_FORMAT':'%(levelname)s:%(message)s'})
runner=CrawlerRunner()
d=runner.crawl(CnblogsSpider)
d.addBoth(lambda _:reactor.stop())
reactor.run()
'''
'''
class MySpider1(scrapy.Spider):
#your first spider definition
...
class MySpider2(scrapy.Spider):
#Your second spider definition
...
#在一个进程中启动多个爬虫
#第一种方法
process=CrawlerProcess()
process.crawl(MySpider1)
process.crawl(MySpider2)
process.start()
#第二种方法
configure_logging()
runner=CrawlerRunner()
runner.crawl(MySpider1)
runner.crawl(MySpider2)
d=runner.join()
d.addBoth(lambda _: reactor.stop())
reactor.run()
#第三种方法
configure_logging()
runner=CrawlerRunner()
@defer.inlineCallbacks
def crawl():
yield runner.crawl(MySpider1)
yield runner.crawl(MySpider2)
reactor.stop()
crawl()
reactor.run()
'''