环境: python3.7 scarpy1.7.3 都是当前最新版
安装: pip install scrapy=1.7.3
创建项目: scrapy startproject demospider
一. 定义item(爬取的数据结构)
编辑items.py文件,定义各项数据
点击(此处)折叠或打开
- import scrapy
- class TutorialItem(scrapy.Item):
- # define the fields for your item here like:
- # name = scrapy.Field()
- link = scrapy.Field()
- title = scrapy.Field()
- text = scrapy.Field()
- image_url = scrapy.Field()
- author = scrapy.Field()
- image_paths = scrapy.Field()
这是最关键的一步,在这里将会解析获取到的html文本,使用scarpy自带的selector解析获取需要的数据。关于selector语法比较多,官方并没有给过多案例,推荐https://www.jianshu.com/p/489c5d21cdc7, 虽然没有过多例子,但是理论比较全,想要的方法基本都可以找到。
在spider目录下新建demo_spider.py文件
点击(此处)折叠或打开
- import scrapy
- from demospider.items import TutorialItem
- class ImageSpider(scrapy.Spider):
- name = 'imagespider' # 应用名,执行时使用
- start_urls = [
- 'http://www.itpub.net/category/yunwei/' # 可以写多个,分别进行爬取处理
- ]
- def parse(self, response): #固定方法,response为每次处理后返回的html,这里主要处理采集第一层页面的数据
- for article in response.css('article.xin_hover'):
- item = TutorialItem() #必须要新建,不然获取的数据都会一样
- item['link'] = article.css('div.post__thumb a::attr("href")').get()
- item['image_url'] = article.css('div.post__thumb img::attr("data-src")').extract()
- item['title'] = article.css('h3.post__title a::text').get()
- item['author'] = article.css('a.entry-author__name::text').get()
- #这里处理第二层连接,文章的具体内容页面
- yield scrapy.Request(item['link'],meta={'item': item}, callback=self.context_parse)
- def context_parse(self,response):
- item = response.meta['item']
- # 有两种方法采集文章内容,这里推荐xpath(xpath属于贪婪匹配,css精确匹配)
- # item['text'] = response.css('div.entry-content p::text').extract()
- item['text'] = response.xpath("//div[@class='entry-content typography-copy']//text()").extract()
- yield item
这步对采集到的数据进行处理,这里直接将数据以json形式存入文本,并且采集文章中的图片
编辑pipeline.py文件
点击(此处)折叠或打开
- import json
- from scrapy.pipelines.images import ImagesPipeline,FilesPipeline
- from scrapy.exceptions import DropItem
- import scrapy
- import requests
- import os
- import hashlib
- from scrapy.utils.python import to_bytes
- BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
- class TutorialPipeline(object):
- def open_spider(self, spider): # pippeline执行的第一个函数,即将把数据存入items.json文件
- self.file = open('items.json', 'w',encoding='utf-8')
- def close_spider(self, spider): # pipeline执行最后一个函数
- self.file.close()
- #注释内容为用requests下载图片,图片不多但是明显感觉到比框架下载慢的多
- def process_item(self, item, spider): # 执行完成函数,返回item实例
- # res = requests.get(item['image_url'][0])
- # image_guid = hashlib.sha1(to_bytes(item['image_url'][0])).hexdigest()
- # item['image_paths'] = 'images/full/%s.jpg' % image_guid
- # if not os.path.exists('images/full/'):
- # os.makedirs('images/full/')
- # with open(os.path.join(item['image_paths']),'wb') as f:
- # f.write(res.content)
- line = json.dumps(dict(item))+'\n'
- self.file.write(line)
- return item
- class MyImagePipline(ImagesPipeline): #使用scarpy的image采集方法
- def get_media_requests(self, item, info): #采集动作,使用item中的图片地址
- for image_url in item['image_url']:
- # print('>>>>>>>>>>>>>>>>>>>>>')
- # print('开始下载图片 '+image_url)
- # print(item)
- # item['image_paths'] = self.file_path(image_url)
- # with open('items_chinaunix.json', 'w',encoding='utf-8') as f:
- # f.write(json.dumps(dict(item))+'\n')
- yield scrapy.Request(image_url,meta={'item': item}) # 采集动作
- def item_completed(self, results, item, info): # 图片采集完成后执行函数,参数意义查看官网
- image_paths = [x['path'] for ok, x in results if ok]
- if not image_paths:
- raise DropItem("Item contains no images")
- item['image_paths'] = image_paths # 将图片在本地的存储地址加入item
- return item
四.设置settings.py中相关配置
settings.py是针对项目的配置,里面配置相当丰富,具体查看官网
这里只定义几项必须的配置,其他默认
点击(此处)折叠或打开
- #设置的pipeline需要在这里启动,每个pipeline处理不同的动作,
- 后面数字表示优先级,越小优先级越高,不超过1000
- ITEM_PIPELINES = {
- 'demospider.pipelines.MyImagePipline': 300,
- 'demospider.pipelines.TutorialPipeline': 301,
- }
- IMAGES_STORE = 'images' # 图片存储的路径
五.执行爬虫应用
执行命令 scrapy crawl imagespider
将会看到执行过程,采集的数据过程,由于数据少,采集过程相当快,不贴截图了,自己练习体会。