用Python网络爬虫框架Scrapy实现对新华网的文章内容爬取



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运行流程大概如下:

  1. 引擎从调度器中取出一个链接(URL)用于接下来的抓取

  2. 引擎把URL封装成一个请求(Request)传给下载器

  3. 下载器把资源下载下来,并封装成应答包(Response)

  4. 爬虫解析Response

  5. 解析出实体(Item),则交给实体管道进行进一步的处理

  6. 解析出的是链接(URL),则把URL交给调度器等待抓

     

2.利用scrapy对新华网抓取

对新华网的文章抓取主要内容包括下四步:

    1. 创建一个新的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

内容:

 

  新华社石家庄527日电 题:小县大作为 新河日日新——河北省新河县以脱贫攻坚统揽发展全局透视

  新华社记者孙杰、朱峰

  脱贫路上快马加鞭,高质发展日新月异。近年来,河北省新河县把脱贫攻坚作为首要政治任务和第一民生工程,统揽经济社会发展全局,以“小县有大志气求大作为”的气魄,形成后发赶超、跨越崛起的良好态势。

  解放思想摆脱“精神贫困”

  新河县位于冀中南平原传统农业区,县域面积仅366平方公里,总人口只有18万人,地势低洼、盐碱沙化、水资源匮乏,是一个典型的人口小县、经济弱县,2012年被列为国家扶贫开发重点县,当时的贫困发生率高达49.78%

  “这里交通并不闭塞,却长期贫困,虽有种种客观因素制约,但重要原因是干部群众存在封闭保守、自我满足思想,消磨锐气,形成弱势心态。”县委书记李群江说,“新河要脱贫发展,必须摆脱‘精神贫困’。”

  为此,新河县连续在全县各级干部中开展“解放思想、抢抓机遇、奋发作为、协同发展”大讨论,同强的比,跟快的赛,向高的攀,县领导带队先后到山东禹城、浙江桐庐等先进地区开展对标学习。县委还向全县党员发出“争做里程碑式党员干部”的动员令,要求大家不断从旧有的固步自封的目标和状态中突破出来,敢走前任未走之路。

  20175月,新河县委、县政府锐意改革大胆探索,突破以往的帮扶模式,将一度负债累累、门可罗雀的县人民医院整体托管给邢台市人民医院,组建紧密医联体,在不改变所有制归属的情况下,形成大型三甲医院和贫困县医院的无缝隙结合,既发挥大医院的辐射带动作用,又提高了贫困地区医院服务能力。

  近年来,新河县政府先后完成了125项行政审批服务事项改革,实现了“一次集中告知、部门并联审批”等目标,并聘请第三方审查扶贫领域政策落实和资金使用情况,积极推进公共服务体制改革,把专业要求高、标准严的供水、污水处理等工作交给市场。解放思想让改革创新活力极大提升。

 

 

猜你喜欢

转载自blog.csdn.net/qq_41593652/article/details/80774697