scrapy学习记录
最近开始学习scrapy,折腾了几天,参考很多资料,做了个小小的图片爬虫。
虽然是个helloworld例子,但真正让我体会到了“纸上觉来终觉浅,得知此事要躬行”的意义,
网上的例子看着简单,但自己写起来是各种问题。过后反思,除编码能力有待提高外,更重要的是刚开始没有吃透框架本身流程,操之过急,本末倒置。
话说回来,不吃点苦头,怎么能体会深刻?就是得折腾,毕竟我还不到八十岁。
闲话少叙,here we go.
scrapy框架
下面是我的理解,不准确之处还请赐教
框架组成
Spiders
作为用户,我们主要的任务就是编写Spiders,指定要爬取的网站,要获取的内容,然后提交给引擎执行
Item Pipeline
Item Pipeline处理Spiders采集、封装数据成的Items。Items在管道之间传送,每个管道对数据进行过滤、保存等操作。
Scrapy Engine
核心部分,连接所有组件,处理Spiders提交的请求,提交到调度器,
Scheduler
接收Scrapy Engine提交的请求,调度,发送请求给Downloader
Downloader
接收Scheduler提交的Request,下载数据,结果以Response对象形式返回给Spiders,由其中定义的回调函数进行处理
爬虫工作流程
用大白话说,流程如下:
- 首先Spiders指定要爬取的页面,向Scrapy Engine提交请求,同时设置请求的回调函数
- 然后Scrapy Engine将请求发给Scheduler,由Scheduler向Downloader发送下载请求,
- Downloader下载完数据后,丢给Spiders,
- 然后Spiders中的回调函数对这一坨原始数据进行解析,获取要提取的内容,封装程Item,丢给PipeLine,
- PipeLine对数据进行下一步处理,如过滤、存储、或重新生成Request,总之各种操作。同一个Item可以经过多个管道,各种被蹂躏。
说了这么多没用的,time to show my shit code
实验过程
工具及版本
工具 | 版本 |
---|---|
Ubuntu | 16.04 |
Scrapy | 1.4 |
Python | 3.5.2 |
项目结构
只有youkuSpider.py
为手动生成的爬虫文件,其他为执行scrapy startproject imgSpider
命令时自动生成的文件。
页面分析
这里以优酷-动画电影页面为例,提取图片和电影名称
分析所示页面格式(如上图),定义好xpath解析形式
编码
这个小例子里,提取的是图片和电影名称,先定义好对应的Item
items.py
# -*- coding: utf-8 -*-
# Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html
import scrapy
class ImgspiderItem(scrapy.Item):
#图片链接,图片名称
image_url = scrapy.Field()
image_name = scrapy.Field()
youkuSpider.py
import scrapy
from imgSpider.items import ImgspiderItem
class YoukuSpider(scrapy.Spider):
#蜘蛛名字
name = "yy"
#要爬去的域,防止小蜘蛛去找妈妈
allowed_domains =["list.youku.com"]
start_urls = ["http://list.youku.com/category/show/c_96_g_动画_s_1_d_1_p_2.html?spm=a2h1n.8251845.0.0"]
#辅助生成下一个要去爬的页面
page_count = 2
#回调
def parse(self,response):
#解析获取的数据
for each in response.xpath("//div[@class='p-thumb']"):
if each:
#获取感兴趣的内容,封装
item = ImgspiderItem()
item["image_url"] = (each.xpath("./img/@src").extract()[0])
item["image_name"] = each.xpath("./img/@alt").extract()[0]
yield item
self.page_count+=1
new_page_url= "http://list.youku.com/category/show/c_96_g_动画_s_1_d_1_p_"+str(self.page_count)+".html?spm=a2h1n.8251845.0.0"
#发送下一个页面的爬行请求,指定回调函数为self.parse
yield scrapy.Request(new_page_url,callback = self.parse)
然后,封装好的item传到我们自定义的Pileline
pipelines.py
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
import scrapy
import os
from scrapy.utils.project import get_project_settings
#Scrapy框架处理图像管道的类
from scrapy.pipelines.images import ImagesPipeline
class MyImagesPipeline(ImagesPipeline):
#获取settints.py中指定的IMAGES_STORE,即下载图片时的存储位置
IMAGES_STORE = get_project_settings().get("IMAGES_STORE")
def get_media_requests(self,item,info):
#提取我们在item中封装的链接,生成request,下载对应的数据
#这里Request的回调由框架进行处理
yield scrapy.Request(item["image_url"])
#下载完后,对文件重命名,否则默认文件名为hash码的形式
def item_completed(self,result,item,info):
#这个是怎么来的,不懂,照官网写的,回头搞清楚,囧
img_path =[ x["path"] for ok,x in result if ok]
os.rename(self.IMAGES_STORE+"/"+img_path[0],self.IMAGES_STORE+"/"+item["image_name"]+".jpg")
#不能忘了
return item
settings.py
# Configure item pipelines
# See http://scrapy.readthedocs.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
'imgSpider.pipelines.MyImagesPipeline': 300,
}
#指定图片文件存储的路径
IMAGES_STORE ="/home/lili/python/spider/imgSpider/imgSpider/spiders/imgs"
要在settings.py添加如下语句,指定使用我们的pilelines。
可以有多个管道,按后面的数字排序,越小越前
实验结果
共爬取30页个页面,每页30张图片,应该共900张。但不知为何少了几张,囧囧
实验总结
迈出了一小步,万事开头难,进步中。O(∩_∩)O哈哈~
先占个坑,回头写上折腾的心得~
PS:Ubuntu实验,window写博客,切换简直精分!