scarpy是python爬虫界最著名的框架,最近使用了下确实很方便,其底层使用的Twisted使用异步非阻塞的方式速度是相当的快(比自己用requests快多了),这里介绍下使用scarpy框架爬取文章和图片,并进行二层爬取文章的内容,然后以dict形式保存为json文件(也可以保存到其他存储介质,如数据库,其他文件存储介质)
环境: 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语法比较多,官方并没有给过多案例,推荐, 虽然没有过多例子,但是理论比较全,想要的方法基本都可以找到。
在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
三. 定义pipeline
这步对采集到的数据进行处理,这里直接将数据以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
将会看到执行过程,采集的数据过程,由于数据少,采集过程相当快,不贴截图了,自己练习体会。
阅读(272589) | 评论(0) | 转发(0) |