使用scrapy框架实现简书页面数据爬取

scrapy框架是基于python的一个爬虫框架,官方文档链接:https://doc.scrapy.org/en/latest/
关于scrapy的安装参考之前的文章 Scrapy 框架的安装(Windows10)
下面以爬取简书的专题页为例说明scrapy框架的使用
我们这次抓取@IT·互联网的专题系列文章,如下图:

《使用scrapy框架实现简书页面数据爬取》 image.png

该页面的链接是http://www.jianshu.com/c/V2CqjW

然后试着用鼠标滚动页面,发现在页面快要滑倒底部时,触发了加载下一页的事件,而此时浏览器地址栏的url并未改变,说明这个页面的页面跳转是通过ajax来实现的,那么js脚本真正执行请求的url是多少呢,通过抓包可以获取这个url。

抓包可以使用fiddler,也可以使用chrome自带的网络工具,这里使用fiddler来抓取这个url,打开fiddler滑动页面到底部,结果下图所示:

《使用scrapy框架实现简书页面数据爬取》 image.png

可以清晰的看出请求url是http://www.jianshu.com/c/V2CqjW?order_by=added_at&page=0,通过改变page的值可以实现分页抓取数据

获取了url之后,我们来分析下页面的元素,看看我们希望抓取的文章信息在页面上是怎么显示的,使用chrome自带的分析工具来分析页面元素,选择需要查看的位置右键鼠标检查即可打开页面元素分析页,如下所示:

《使用scrapy框架实现简书页面数据爬取》 image.png

如上,可以很方便的找出文章列表是用一个ul标签实现的,里面的每一个文章都是一个li。

好了,简单的分析了页面元素后,我们开始着手搭建一个scrapy框架,进入一个希望存放项目的路径,地址栏输入cmd回车,打开window控制台,输入指令

  scrapy startproject jianshu

创建了一个名字为简书的项目,使用pycharm打开项目,项目结构如下所示:

《使用scrapy框架实现简书页面数据爬取》 image.png

在items.py文件中定义一个实体类JianshuItem:

import scrapy


class JianshuItem(scrapy.Item):

    # id, 使用mongodb,用_id作为主键
    _id = scrapy.Field()
    # 博客名
    blog_title = scrapy.Field()
    # 作者
    author = scrapy.Field()
    # 发布时间
    date = scrapy.Field()
    # 内容url
    content_url = scrapy.Field()
    # 内容简介
    content_summary = scrapy.Field()
    # 配图,可以为空
    content_figure_url = scrapy.Field()
    # 作者头像,可以为空
    author_icon_url = scrapy.Field()

然后我们来实现一下爬虫类的编写,可以在spider文件夹下创建一个py文件用来实现爬虫逻辑,也可以使用命令直接创建一个:

    scrapy genspider jianshuspider www.jianshu.com

创建格式如下:

    scrapy genspider [options] <name> <domain>

这样就在spider文件夹下创建了一个名字叫jianshuspider.py的文件,我们在这个文件中实现爬虫的逻辑,代码如下:

            # -*- coding: utf-8 -*-
  import scrapy
  from jianshu.items import JianshuItem
  from abc import abstractmethod


  class JianshuBaseSpider(scrapy.Spider):
      base_url = "www.jianshu.com"
      allowed_domains = [base_url]
      category_code = ''
      common_url = ''
      url = ''

      @abstractmethod
      def parse_more(self):
          pass

      def get_full_url(self, url):
          return self.base_url + url

      def parse(self, response):
          for i in response.xpath("//ul[@class='note-list']/li"):
              item = JianshuItem()
              try:
                  item['_id'] = i.xpath("./@id").extract()[0]
              except Exception as e:
                  print(e)
                  return
              try:
                  item['blog_title'] =             
                        i.xpath(".//div[@class='content']/a/text()").extract()[0]
              except Exception as e:
                  item['blog_title'] = ''
              try:
                  item['content_url'] = 
                      self.get_full_url(i.xpath(".//div[@class='content']/a/@href")
                                    .extract()[0])
              except Exception as e:
                  item['content_url'] = ''
              try:
                  item['content_summary'] =       
                           i.xpath(".//div[@class='content']/p/text()").extract()[0]
              except Exception as e:
                  item['content_summary'] = ''
              try:
                  item['content_figure_url'] =     
                         self.get_full_url(i.xpath("./a/img/@src").extract()[0])
              except Exception as e:
                  item['content_figure_url'] = ''
              try:
                  item['author'] = 
                          i.xpath(".//div[@class='author']/div/a/text()").extract()[0]
              except Exception as e:
                  item['author'] = ''
              try:
                  item['date'] = i.xpath(".//div[@class='author']/div/span/@data-
                                   shared-at").extract()[0]
              except Exception as e:
                  item['date'] = ''
              try:
                  item['author_icon_url'] = 
                 self.get_full_url(i.xpath(".//div[@class='author']/a/@href")
                                            .extract()[0])
              except Exception as e:
                  item['author_icon_url'] = ''
              yield item
          # 交由子类实现具体的处理
          yield self.parse_more()


'''@IT·互联网 专题'''
  class ITSpider(JianshuBaseSpider):
      name = 'ITSpider'
      page = 0
      category_code = 'V2CqjW'
      common_url = 'http://www.jianshu.com/c/' + category_code + '?        
                          order_by=added_at&page='
      url = common_url + str(page)
      start_urls = [url]

      def parse_more(self):
          self.page += 1
          # 每天抓20页
          if self.page > 20:
              return
          return scrapy.Request(self.common_url + str(self.page),       
                       callback=self.parse)

代码很简单,此处不再废话了,代码中使用了yield语句,用途是将结果提交到管道流pipeline,管道流来帮我们实现数据的持久化处理,打开pipeline.py文件,添加如下代码:

  from pymongo import MongoClient

  class JianshuPipeline(object):

      def __init__(self):
          self.client = MongoClient('localhost', 27017)
          self.db_jianshu = self.client.jianshu

      def process_item(self, item, spider):
          json_item = dict(item)
          self.db_jianshu.jianshu.update({'_id': json_item['_id']}, json_item,     
                     upsert=True)
          return item

      def close_spider(self, spider):
          self.client.close()

我们使用管道流将数据存储在mongodb数据库中,mongodb是一种nosql数据库,官方链接:https://docs.mongodb.com/manual/
参考资料:
http://api.mongodb.com/python/current/api/pymongo/index.html
http://wiki.jikexueyuan.com/project/mongodb/
安装:http://www.jianshu.com/p/5598f1dcbb98

下面简单的描述下mongodb的安装和使用,下载mongodb软件安装包并安装,mongodb分为服务端和客户端,mongod.exe是服务端,而mongo.exe是客户端,cmd到mongodb的bin目录下(也可以将mongod加入到环境变量),执行指令:

   mongod --dbpath "d:\mongotest\mongodb\data"

后面的路径为数据存放路径,这样就开启了服务端进程
将mongo.exe的路径,加入到环境变量,然后在控制台输入mongo即可开启一个客户端进程mongo shell,mongo的基本指令参见官方文档。
在此例中,我们使用python的客户端,安装pymongo包:

  pip install pymongo

用python代码实现将数据存入mongo数据库的操作如上面的代码所示。

settings:

settings.py中需要更改一些设置:

     # Obey robots.txt rules
      ROBOTSTXT_OBEY = False

关闭遵守robots协议

    DOWNLOAD_DELAY = 3

设置下载延迟为3秒,避免下载过快被封ip

      DEFAULT_REQUEST_HEADERS = {
                 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) 
                 AppleWebKit/537.36 (KHTML, like Gecko) 
                 Chrome/59.0.3071.115 Safari/537.36',
     }

更改默认请求头,这里使用的是chrome浏览器的

       ITEM_PIPELINES = {
         'jianshu.pipelines.JianshuPipeline': 300,
       }

启用pipeline

这样,基本就大功告成了,我们可以爬取@IT·互联网页面的所有博客,并存入mongo数据库。

《使用scrapy框架实现简书页面数据爬取》 image.png

    原文作者:牒儿布
    原文地址: https://www.jianshu.com/p/67f27b8109f6
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞