1.Scrapy框架简介
Scrapy,Python开发的一个快速,高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据。Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试。
Scrapy主要包括了以下组件:
引擎(Scrapy)
用来处理整个系统的数据流处理, 触发事务(框架核心)调度器(Scheduler)
用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址下载器(Downloader)
用于下载网页内容, 并将网页内容返回给蜘蛛(Scrapy下载器是建立在twisted这个高效的异步模型上的)爬虫(Spiders)
爬虫是主要干活的, 用于从特定的网页中提取自己需要的信息, 即所谓的实体(Item)。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面项目管道(Pipeline)
负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据。下载器中间件(Downloader Middlewares)
位于Scrapy引擎和下载器之间的框架,主要是处理Scrapy引擎与下载器之间的请求及响应。爬虫中间件(Spider Middlewares)
介于Scrapy引擎和爬虫之间的框架,主要工作是处理蜘蛛的响应输入和请求输出。调度中间件(Scheduler Middewares)
介于Scrapy引擎和调度之间的中间件,从Scrapy引擎发送到调度的请求和响应。
Scrapy运行流程大概如下:
引擎从调度器中取出一个链接(URL)用于接下来的抓取。
引擎把URL封装成一个请求(Request)传给下载器。
下载器把资源下载下来,并封装成应答包(Response)。
爬虫解析Response。
解析出实体(Item),则交给实体管道进行进一步的处理。
解析出的是链接(URL),则把URL交给调度器等待抓取。
2.利用scrapy对新华网抓取
对新华网的文章抓取主要内容包括以下四步:
-
创建一个新的Scrapy Project
2. 定义需要从网页中提取的元素Item
3. 实现一个Spider类,通过接口完成爬取URL和提取Item的功能
4. 实现一个Item PipeLine类,完成Item的存储功能2.1.新建工程
首先,为我们的爬虫新建一个工程,首先进入一个目录(任意一个我们用来保存代码的目录),执行:
scrapy startproject xinhua
最后的xinhua就是项目名称。这个命令会在当前目录下创建一个新目录Domz,结构如下
xinhua/
scrapy.cfg
xinhua/
__init__.py
items.py
pipelines.py
settings.py
spiders/
__init__.py
scrapy.cfg: 项目配置文件
items.py: 需要提取的数据结构定义文件
pipelines.py: 管道定义,用来对items里面提取的数据做进一步处理,如保存等
settings.py: 爬虫配置文件
spiders: 放置spider的目录2.2.定义Item
在items.py里面定义我们要抓取的数据:
import scrapy class GetUrlItem(scrapy.Item): #定义抓取新华网的频道链接 # define the fields for your item here like: url = scrapy.Field() class GetArticleItem(scrapy.Item):#定义抓取新华网频道链接中的文章链接 # define the fields for your item here like: url_article = scrapy.Field() class GetContentItem(scrapy.Item):#定义抓取文章链接中的文章内容 # define the fields for your item here like: title = scrapy.Field() time = scrapy.Field() content = scrapy.Field()
这里我们需要获取xinhua页面上的频道链接,文章链接,文章内容,所以定义一个对应的items结构。
2.3.实现Spider
spider只是一个继承字scrapy.spider.BaseSpider的Python类,有三个必需的定义的成员
name: 名字,这个spider的标识
start_urls: 一个url列表,spider从这些网页开始抓取
parse(): 一个方法,当start_urls里面的网页抓取下来之后需要调用这个方法解析网页内容,同时需要返回下一个需要抓取的网页,或者返回items列表所以在spiders目录下新建三个spider,分别是get_url.py,get_article.py,get_content.py
1.get_url.py
import scrapy from xinhuawang.items import GetUrlItem class GetUrl(scrapy.Spider): name = "get_url" allowed_domains = ["xinhuanet.com"] start_urls = ["http://www.xinhuanet.com/"] def parse(self, response): for sel in response.xpath('//*[@class="navCont clearfix"]/ul/li/a/@href'): #返回一个相对于当前选中节点的选择器列表 item = GetUrlItem() item['url'] = sel.extract()#返回选择器(列表)对应的节点的字符串(列表) yield item
提取数据到Items里面,主要用到XPath提取网页数据:
scrapy有提供两个XPath选择器,HtmlXPathSelector和XmlXPathSelector,一个用于HTML,一个用于XML,XPath选择器有三个方法
select(xpath): 返回一个相对于当前选中节点的选择器列表(一个XPath可能选到多个节点)
extract(): 返回选择器(列表)对应的节点的字符串(列表)
re(regex): 返回正则表达式匹配的字符串(分组匹配)列表
同理,我们通过set_url.py对频道链接抓取,并保存在list.txt文件中,再次用get_article对list.txt中的文章链接进行抓取。
import scrapy,re,os from xinhua.items import GetArticleItem import sys import importlib importlib.reload(sys) class GetArticle(scrapy.Spider): name = "get_article" allowed_domains = ["xinhuanet.com/"] start_urls = [] if os.path.exists('list.txt'): with open('list.txt','r') as f: for line in f.readlines(): start_urls.append(line[0:-1]) def parse(self, response): for sel in response.xpath('//li/a/@href'): item = GetArticleItem() item['url_article'] = sel.extract() yield item
同理,我们通过set_article.py对频道链接抓取,并保存在article.txt文件中,再次用get_content.py对article.txt中的文章标题、发布时间、内容进行抓取。
import scrapy,re,os from xinhua.items import GetContentItem import sys import importlib importlib.reload(sys) class GetContent(scrapy.Spider): name = "get_content" allowed_domains = ["xinhuanet.com"] start_urls = [] if os.path.exists('article.txt'): with open('article.txt','r') as f: for line in f.readlines(): #返回正则表达式匹配的字符串(分组匹配)列表 if re.search(r'xinhuanet.com',line): start_urls.append(line[0:-1]) def parse(self, response): item =GetContentItem() #提取数据到items里面去 item['title'] = response.xpath('//title/text()').extract_first() #返回选择器对应的节点的文章标题列表 item['time'] = response.xpath('//*[@class="h-time"]/text()').extract_first() #返回选择器对应的节点的文章发布时间列表 content = response.xpath('//*[@class="main"]') #返回选择器对应的节点的文章段落内容列表 if len(content) > 0: item['content'] = content[0].xpath('string(.)').extract_first() yield item
2.4.实现PipeLine
PipeLine用来对Spider返回的Item列表进行保存操作,可以写入到文件、或者数据库等。
PipeLine只有一个需要实现的方法:process_item,例如我们将Item保存到一个文件中
class XinhuaPipeline(object): def process_item(self, item, spider): if 'url' in item: #将get_url.py爬取到的内容保存到list.txt with open('list.txt','a') as f: f.write("http://www.xinhuanet.com/"+item['url']) f.write('\n') return item if 'url_article' in item: #将get_article.py爬取到的内容保存到article.txt with open('article.txt','a') as f: f.write(item['url_article']) f.write('\n') return item if 'content' in item: #将get_content.py爬取到的内容保存到list.txt with open('content.txt','a') as f: #print(item['title']) f.write('标题:') f.write(item['title']) f.write('\t') f.write('时间:') f.write(item['time']) f.write('\t') f.write('内容:') content = item['content'] a = '' for b in content: if b != '\n': a = a + b content = a f.write(content) f.write('\n') return item
2.5.运行结果
到现在,我们就完成了一个基本的爬虫的实现,可以输入下面的命令来分别启动这三个Spider:
1.scrapy crawl get_url
输出结果保存至list.txt文件中。
以下为list.txt中的部分内容:
http://www.xinhuanet.com/politics/
http://www.xinhuanet.com/local/index.htm
http://www.xinhuanet.com/legal/index.htm
http://www.xinhuanet.com/politics/leaders/index.htm
http://www.xinhuanet.com/renshi/index.htm
http://www.xinhuanet.com/politics/xhll.htm
http://www.xinhuanet.com/world/index.htm
http://www.xinhuanet.com/mil/index.htm
http://www.xinhuanet.com/video/xhft.htm
http://www.xinhuanet.com/gangao/index.htm
http://www.xinhuanet.com/tw/index.htm
http://www.xinhuanet.com/overseas/index.htm
http://www.xinhuanet.com/fortune/
http://www.xinhuanet.com/auto/index.htm
http://www.xinhuanet.com/house/index.htm
http://www.xinhuanet.com/http://education.news.cn/
http://www.xinhuanet.com/tech/index.htm
http://www.xinhuanet.com/energy/index.htm
2.scrapy crawl get_article
输出结果保存至article.txt文件中。
以下为article.txt中的部分内容:
http://www.xinhuanet.com/legal/2018-05/27/c_1122895076.htm
http://www.xinhuanet.com/world/2018-05/26/c_129880754.htm
http://www.xinhuanet.com/world/2018-05/25/c_1122890296.htm
http://www.yxcps.cn/?from=xh00001
http://www.xinhuanet.com/house/2018-05-21/c_1122860546.htm
http://www.xinhuanet.com/overseas/2018-05/24/c_129879221.htm
http://www.xinhuanet.com/politics/2018-05/27/c_1122895228.htm
http://www.xinhuanet.com/local/2018-05/27/c_1122895239.htm
http://www.xinhuanet.com/local/2018-05/27/c_1122895238.htm
http://www.xinhuanet.com/politics/2018-05/27/c_1122895161.htm
http://www.xinhuanet.com/politics/2018-05/27/c_1122895159.htm
http://www.xinhuanet.com/politics/2018-05/27/c_1122895156.htm
http://www.xinhuanet.com/auto/2018-05/27/c_1122893978.htm
http://www.xinhuanet.com/tw/2018-05/27/c_129881014.htm
3.scrapy crawl get_content
输出结果保存至content.txt文件中。
以下为content.txt中的部分内容:
标题:
小县大作为 新河日日新——河北省新河县以脱贫攻坚统揽发展全局透视-新华网
时间: 2018-05-27 19:14:17
内容:
新华社石家庄5月27日电 题:小县大作为 新河日日新——河北省新河县以脱贫攻坚统揽发展全局透视
新华社记者孙杰、朱峰
脱贫路上快马加鞭,高质发展日新月异。近年来,河北省新河县把脱贫攻坚作为首要政治任务和第一民生工程,统揽经济社会发展全局,以“小县有大志气求大作为”的气魄,形成后发赶超、跨越崛起的良好态势。
解放思想摆脱“精神贫困”
新河县位于冀中南平原传统农业区,县域面积仅366平方公里,总人口只有18万人,地势低洼、盐碱沙化、水资源匮乏,是一个典型的人口小县、经济弱县,2012年被列为国家扶贫开发重点县,当时的贫困发生率高达49.78%。
“这里交通并不闭塞,却长期贫困,虽有种种客观因素制约,但重要原因是干部群众存在封闭保守、自我满足思想,消磨锐气,形成弱势心态。”县委书记李群江说,“新河要脱贫发展,必须摆脱‘精神贫困’。”
为此,新河县连续在全县各级干部中开展“解放思想、抢抓机遇、奋发作为、协同发展”大讨论,同强的比,跟快的赛,向高的攀,县领导带队先后到山东禹城、浙江桐庐等先进地区开展对标学习。县委还向全县党员发出“争做里程碑式党员干部”的动员令,要求大家不断从旧有的固步自封的目标和状态中突破出来,敢走前任未走之路。
2017年5月,新河县委、县政府锐意改革大胆探索,突破以往的帮扶模式,将一度负债累累、门可罗雀的县人民医院整体托管给邢台市人民医院,组建紧密医联体,在不改变所有制归属的情况下,形成大型三甲医院和贫困县医院的无缝隙结合,既发挥大医院的辐射带动作用,又提高了贫困地区医院服务能力。
近年来,新河县政府先后完成了125项行政审批服务事项改革,实现了“一次集中告知、部门并联审批”等目标,并聘请第三方审查扶贫领域政策落实和资金使用情况,积极推进公共服务体制改革,把专业要求高、标准严的供水、污水处理等工作交给市场。解放思想让改革创新活力极大提升。