用Scrapy爬取一篇新闻

Scrapy简介

Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。

Scrapy入门

主要完成以下几个步骤:
  • 创建一个Scrapy项目
  • 定义提取的Item
  • 编写爬取网站的 spider 并提取 Item
  • 编写 Item Pipeline 来存储提取到的Item(即数据)
创建项目:

在开始爬取之前,必须创建一个新的Scrapy项目。 进入打算存储代码的目录中:
用Scrapy爬取一篇新闻_第1张图片
运行下列命令:

scrapy startproject scrapy_demo

该命令将会创建包含下列内容的 scrapy_demo 目录:

scrapy_demo/
    scrapy.cfg
    scrapy_demo/
        __init__.py
        items.py
        pipelines.py
        settings.py
        spiders/
            __init__.py
            ...

这些文件分别是:

  • scrapy.cfg: 项目的配置文件
  • scrapy_demo/: 该项目的python模块。之后将在此加入代码
  • scrapy_demo/items.py: 项目中的item文件
  • scrapy_demo/pipelines.py: 项目中的pipelines文件
  • scrapy_demo/settings.py: 项目的设置文件
  • scrapy_demo/spiders/: 放置spider代码的目录
定义Item:

Item 是保存爬取到的数据的容器;其使用方法和python字典类似, 并且提供了额外保护机制来避免拼写错误导致的未定义字段错误。

  • 在这里尝试爬取新浪新闻滚动版,点开任意一条新闻,查看网页源代码,从中观察到可以提取的信息内容,这里列出其中两种:
    • title
    • description
  • 通过创建一个 scrapy.Item 类, 并且定义类型为 scrapy.Field 的类属性来定义一个Item。 首先根据需要从刚才的网站上获取到的数据对item进行建模。 需要从中获取以上几种信息。 对此,在item中定义相应的字段。编辑 scrapy_demo 目录中的 items.py 文件:
import scrapy
class ScrapyDemoItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    title = scrapy.Field()
    tags = scrapy.Field()
    keywords = scrapy.Field()
    description = scrapy.Field()

通过定义item, 可以很方便的使用Scrapy的其他方法。而这些方法需要知道item的定义。

编写爬虫(Spider)

Spider是用户编写用于从单个网站(或者一些网站)爬取数据的类。其包含了一个用于下载的初始URL,如何跟进网页中的链接以及如何分析页面中的内容, 提取生成 item 的方法。为了创建一个Spider,必须继承 scrapy.Spider 类, 且定义以下三个属性:

  • name: 用于区别Spider。 该名字必须是唯一的,不可以为不同的Spider设定相同的名字。
  • start_urls: 包含了Spider在启动时进行爬取的url列表。 因此,第一个被获取到的页面将是其中之一。 后续的URL则从初始的URL获取到的数据中提取。
  • parse() 是spider的一个方法。 被调用时,每个初始URL完成下载后生成的 Response 对象将会作为唯一的参数传递给该函数。 该方法负责解析返回的数据(response data),提取数据(生成item)以及生成需要进一步处理的URL的 Request 对象。
    以下为Spider代码,保存在 scrapy_demo/spiders 目录下的 demo_spider.py 文件中:
import scrapy
class DemoSpider(scrapy.spiders.Spider):
    name = "demo"
    start_urls = [
        "https://mil.news.sina.com.cn/jssd/2020-04-14/doc-iircuyvh7664688.shtml"
    ]
    def parse(self, response):
        # filename = response.url.split("/")[-2]
        filename = 'news'
        with open(filename, 'wb') as f:
            f.write(response.body)
  • 爬取
    进入项目的根目录下,并执行命令启动spider:在这里插入图片描述
    执行后得到类似的输出:
    用Scrapy爬取一篇新闻_第2张图片
    可以在文件夹中发现创建了一个名为news的输出,该输出可以用vscode打开查看:
    在这里插入图片描述
    解释:Scrapy为Spider的 start_urls 属性中的每个URL创建了 scrapy.Request 对象,并将 parse 方法作为回调函数(callback)赋值给了Request。Request对象经过调度,执行生成 scrapy.http.Response 对象并送回给spider parse() 方法。

  • 提取Item
    从news中可以看出,网页的相关信息都保存在news中:
    用Scrapy爬取一篇新闻_第3张图片
    现在就要从其中提取出我们需要的信息,这里用到了一种基于XPath和CSS表达机制的工具: Scrapy Selectors。这里表示XPath表达式的示例及对应的含义:

    • /html/head/title:选择HTML文档中标签内的元素
    • /html/head/title/text():选择上面提到的元素的文字
    • //td:选择所有的元素
    • //div[@class=“mine”]:选择所有具有class="mine"属性的div元素

    Selector有四个基本的方法(单击相应的方法可以看到详细的API文档):

    • xpath():预定的xpath表达式,返回该表达式所对应的所有异步的选择器列表列表。
    • css():初始CSS表达式,返回该表达式所对应的所有队列的选择器列表。
    • extract():序列化该例程为unicode字符串并返回列表。
    • re():根据初步的正则表达式对数据进行提取,返回unicode字符串列表列表。

    具体尝试如下,基本可以一目了然:

    • 首先打开Scrapy shell,在shell中观察网页信息:在项目根目录下执行以下命令:在这里插入图片描述会显示如下:用Scrapy爬取一篇新闻_第4张图片

    • 在其中输入response.body会得到response对象中的body信息。
      用Scrapy爬取一篇新闻_第5张图片

    • 结合用vscode打开的news文件,做以下尝试:用Scrapy爬取一篇新闻_第6张图片
      用Scrapy爬取一篇新闻_第7张图片
      用Scrapy爬取一篇新闻_第8张图片
      用Scrapy爬取一篇新闻_第9张图片用Scrapy爬取一篇新闻_第10张图片
      可以看出距离我们像提取的文章信息已经很近了,接下来要完成的就是去掉一些符号、换行等

      import re
      class DemoSpider(scrapy.spiders.Spider):
          name = "demo"
          start_urls = [
              "https://mil.news.sina.com.cn/jssd/2020-04-14/doc-iircuyvh7664688.shtml"
          ]
      
      
          def parse(self, response):
              title = response.xpath('//title/text()').extract()
              title = ''.join(title)
              content = response.xpath('//div[@class="article" and @id="article"]//p/text() ').extract()
              # 将list里的所有内容串起来变成字符串
              content = ''.join(content)
              content = re.sub(r'\u3000', '', content)
              content = content.replace( "▲", '')
              print("title:{}".format(title))
              print("content:{}".format(content))
      
    • 在项目的根目录的命令行输入:scrapy crawl demo,运行结果如下:用Scrapy爬取一篇新闻_第11张图片
      可以看出信息被成功输出

  • 使用item
    Item 对象是自定义的python字典。 一般来说,Spider将会将爬取到的数据以 Item 对象返回。所以为了将爬取的数据返回,最终的代码将是:

      ```python
      import scrapy
      import re
      from scrapy_demo.items import ScrapyDemoItem
      class DemoSpider(scrapy.spiders.Spider):
        name = "demo"
        start_urls = [
            "https://mil.news.sina.com.cn/jssd/2020-04-14/doc-iircuyvh7664688.shtml"
        ]
      
      
        def parse(self, response):
            item = ScrapyDemoItem()
            title = response.xpath('//title/text()').extract()
            title = ''.join(title)
            content = response.xpath('//div[@class="article" and @id="article"]//p/text() ').extract()
            # 将list里的所有内容串起来变成字符串
            content = ''.join(content)
            content = re.sub(r'\u3000', '', content)
            content = content.replace( "▲", '')
            # print("title:{}".format(title))
            # print("content:{}".format(content))
            item['title'] = title
            item['content'] = content
            yield item
      ```
    
  • 将爬取到的数据保存为本地json
    项目的根目录下,在命令行输入:在这里插入图片描述
    即可将爬取数据保存为json且编码为“UTF-8”在这里插入图片描述

你可能感兴趣的:(用Scrapy爬取一篇新闻)