使用scarpy爬取文章并保存为json文本

272590阅读 0评论2019-08-13 fengqiyunyong123
分类:Web开发

        scarpy是python爬虫界最著名的框架,最近使用了下确实很方便,其底层使用的Twisted使用异步非阻塞的方式速度是相当的快(比自己用requests快多了),这里介绍下使用scarpy框架爬取文章和图片,并进行二层爬取文章的内容,然后以dict形式保存为json文件(也可以保存到其他存储介质,如数据库,其他文件存储介质)
    
        环境: python3.7   scarpy1.7.3  都是当前最新版

        安装: pip install scrapy=1.7.3

        创建项目:  scrapy startproject demospider

       
  一. 定义item(爬取的数据结构)
    编辑items.py文件,定义各项数据
    

点击(此处)折叠或打开

  1. import scrapy


  2. class TutorialItem(scrapy.Item):
  3.     # define the fields for your item here like:
  4.     # name = scrapy.Field()
  5.     link = scrapy.Field()
  6.     title = scrapy.Field()
  7.     text = scrapy.Field()
  8.     image_url = scrapy.Field()
  9.     author = scrapy.Field()
  10.     image_paths = scrapy.Field()
    二. 定义爬取方法
        这是最关键的一步,在这里将会解析获取到的html文本,使用scarpy自带的selector解析获取需要的数据。关于selector语法比较多,官方并没有给过多案例,推荐, 虽然没有过多例子,但是理论比较全,想要的方法基本都可以找到。
        在spider目录下新建demo_spider.py文件
        

点击(此处)折叠或打开

  1. import scrapy
  2. from demospider.items import TutorialItem




  3. class ImageSpider(scrapy.Spider):

  4.     name = 'imagespider'       # 应用名,执行时使用
  5.     start_urls = [
  6.         'http://www.itpub.net/category/yunwei/'   # 可以写多个,分别进行爬取处理
  7.     ]

  8.     def parse(self, response):                #固定方法,response为每次处理后返回的html,这里主要处理采集第一层页面的数据
  9.         for article in response.css('article.xin_hover'):
  10.             item = TutorialItem()  #必须要新建,不然获取的数据都会一样                        
  11.             item['link'] = article.css('div.post__thumb a::attr("href")').get()
  12.             item['image_url'] = article.css('div.post__thumb img::attr("data-src")').extract()
  13.             item['title'] = article.css('h3.post__title a::text').get()
  14.             item['author'] = article.css('a.entry-author__name::text').get()
  15.             #这里处理第二层连接,文章的具体内容页面
  16.             yield scrapy.Request(item['link'],meta={'item': item}, callback=self.context_parse)


  17.     def context_parse(self,response):
  18.         item = response.meta['item']
  19.         # 有两种方法采集文章内容,这里推荐xpath(xpath属于贪婪匹配,css精确匹配)
  20.         # item['text'] = response.css('div.entry-content p::text').extract()
  21.         item['text'] = response.xpath("//div[@class='entry-content typography-copy']//text()").extract()
  22.         yield item
     三. 定义pipeline
    这步对采集到的数据进行处理,这里直接将数据以json形式存入文本,并且采集文章中的图片
   编辑pipeline.py文件
   

点击(此处)折叠或打开

  1. import json
  2. from scrapy.pipelines.images import ImagesPipeline,FilesPipeline
  3. from scrapy.exceptions import DropItem
  4. import scrapy
  5. import requests
  6. import os
  7. import hashlib
  8. from scrapy.utils.python import to_bytes

  9. BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

  10. class TutorialPipeline(object):

  11.     def open_spider(self, spider):     # pippeline执行的第一个函数,即将把数据存入items.json文件
  12.         self.file = open('items.json', 'w',encoding='utf-8')

  13.     def close_spider(self, spider):    # pipeline执行最后一个函数
  14.         self.file.close()

  15.        #注释内容为用requests下载图片,图片不多但是明显感觉到比框架下载慢的多
  16.     def process_item(self, item, spider):   # 执行完成函数,返回item实例
  17.         # res = requests.get(item['image_url'][0])
  18.         # image_guid = hashlib.sha1(to_bytes(item['image_url'][0])).hexdigest()
  19.         # item['image_paths'] = 'images/full/%s.jpg' % image_guid
  20.         # if not os.path.exists('images/full/'):
  21.         # os.makedirs('images/full/')
  22.         # with open(os.path.join(item['image_paths']),'wb') as f:
  23.         # f.write(res.content)
  24.         line = json.dumps(dict(item))+'\n'
  25.         self.file.write(line)
  26.         return item


  27. class MyImagePipline(ImagesPipeline):    #使用scarpy的image采集方法

  28.     def get_media_requests(self, item, info):   #采集动作,使用item中的图片地址
  29.         for image_url in item['image_url']:
  30.             # print('>>>>>>>>>>>>>>>>>>>>>')
  31.             # print('开始下载图片 '+image_url)
  32.             # print(item)
  33.             # item['image_paths'] = self.file_path(image_url)
  34.             # with open('items_chinaunix.json', 'w',encoding='utf-8') as f:
  35.             # f.write(json.dumps(dict(item))+'\n')
  36.             yield scrapy.Request(image_url,meta={'item': item})   # 采集动作


  37.     def item_completed(self, results, item, info):  # 图片采集完成后执行函数,参数意义查看官网
  38.         image_paths = [x['path'] for ok, x in results if ok]
  39.         if not image_paths:
  40.             raise DropItem("Item contains no images")
  41.         item['image_paths'] = image_paths           #  将图片在本地的存储地址加入item
  42.         return item

四.设置settings.py中相关配置
settings.py是针对项目的配置,里面配置相当丰富,具体查看官网
这里只定义几项必须的配置,其他默认

点击(此处)折叠或打开

  1. #设置的pipeline需要在这里启动,每个pipeline处理不同的动作,
  2. 后面数字表示优先级,越小优先级越高,不超过1000
  3. ITEM_PIPELINES = {
  4.    'demospider.pipelines.MyImagePipline': 300,         
  5.    'demospider.pipelines.TutorialPipeline': 301,
  6. }

  7. IMAGES_STORE = 'images'          # 图片存储的路径


五.执行爬虫应用

执行命令     scrapy crawl imagespider       

将会看到执行过程,采集的数据过程,由于数据少,采集过程相当快,不贴截图了,自己练习体会。




上一篇:详解使用restframwork api 实现各类http请求
下一篇:记录linux升级gcc导致的故障