scrapy (2)下载图片及存储信息

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 MongoDB,通用型 2核4GB
简介:

1scrapy项目的使用(利用item收集抓取的返回值)

1、创建scrapy项目

1
2
3
4
5
6
scrapy startproject booklist
New Scrapy project  'booklist' , using template directory  '/usr/local/lib/python3.6/site-packages/scrapy/templates/project' , created  in :
     /Users/yuanjicai/booklist
You can start your first spider with:
     cd  booklist
     scrapy genspider example example.com

2、定义要抓取内容的字段(用于回收抓取的数据)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cat booklist / 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  BooklistItem(scrapy.Item):
     # define the fields for your item here like:
     # name = scrapy.Field()
     name  =  scrapy.Field()
     author  =  scrapy.Field()
     publisher  =  scrapy.Field()
     editor_date  =  scrapy.Field()
     description  =  scrapy.Field()

3、编写spider进行抓取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
cat booklist / spiders / bookspider.py
import  scrapy
from  booklist.items  import  BooklistItem
class  BookSpider(scrapy.Spider):
     name  =  'booklist'
     start_urls  =  [ 'http://www.chinavalue.net/BookInfo/BookList.aspx?page=1' ]
     def  parse( self ,response):
         yield  scrapy.Request(response.urljoin( "?page=1" ),callback = self .parse_page)
         for  item  in  response.xpath( '//div[@id="ctl00_ContentPlaceHolder1_pagerBook"]/a/@href' ).extract():
             fullurl = response.urljoin(item)
             yield  scrapy.Request(fullurl,callback = self .parse_page)
     def  parse_page( self ,response):
         for  item  in  response.xpath( '//div[@id="divBookList"]/div/div[2]/a[1]' ):
             detail_url = response.urljoin(item.xpath( '@href' ).extract()[ 0 ])
             yield  scrapy.Request(detail_url,callback = self .parse_bookdetail)
     def  parse_bookdetail( self ,response):
         bookinfo = BooklistItem()
         basic_info = response.xpath( '//*[@id="Container"]/div[6]/div[1]/div[2]/div[1]/div[2]' )
         bookinfo[ 'name' ] = basic_info.xpath( 'div[1]/text()' ).extract()[ 0 ].strip()
         bookinfo[ 'author' ] = basic_info.xpath( 'div[2]/text()' ).extract()[ 0 ].strip()
         bookinfo[ 'publisher' ] = basic_info.xpath( 'div[3]/text()' ).extract()[ 0 ].strip()
         bookinfo[ 'editor_date' ] = basic_info.xpath( 'div[4]/text()' ).extract()[ 0 ].strip()
         bookinfo[ 'description' ] = response.xpath( '//*[@id="ctl00_ContentPlaceHolder1_pnlIntroBook"]/div[2]/text()' ).extract()[ 0 ].strip()
         yield  bookinfo

parse函数中的“for循环”处理“下一页”的link(下图所示)

11.png

parse_page函数负责解析每一页书单中 各item 标题的link(如下图所示)

22.png

parse_bookdetail 负责解析每本书的详细属性及内容(如下图所示)

33.png


4、运行项目

1
scrapy crawl booklist -o book-info.csv

上例中将抓取的信息通过yield返回给item中的各字段,然后再通过 output 选项 存储到 book-info.csv 文件中。


例2:scrapy下载图片,并将抓取信息存储到指定位置(文件、mysql、mongodb)

创建项目(下载图片)

1
2
bogon:scrapy yuanjicai$ scrapy startproject bookinfo
bogon:douban_booklist yuanjicai$  cd  bookinfo/

cat bookinfo/items.py   #在item中定义抓取的各字段名,并定义image_urls、image_paths

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# -*- 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  BookinfoItem(scrapy.Item):
     # define the fields for your item here like:
     # name = scrapy.Field()
     name  =  scrapy.Field()
     author  =  scrapy.Field()
     publisher  =  scrapy.Field()
     price  =  scrapy.Field()
     rating  =  scrapy.Field()
     editor_date  =  scrapy.Field()
     images  =  scrapy.Field()
     image_urls  =  scrapy.Field()
     image_paths  =  scrapy.Field()

vim bookinfo/settings.py    #通过settings指定抓取时使用的header、agent、pipeline、图片或文件保存的位置、img过期时间、mysql用户名/密码/端口、mongo用户名/密码/端口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
grep  -E - v  '^(#|$)'  bookinfo /settings .py
BOT_NAME =  'bookinfo'
SPIDER_MODULES = [ 'bookinfo.spiders' ]
NEWSPIDER_MODULE =  'bookinfo.spiders'
ROBOTSTXT_OBEY = True
#from faker import Factory
#f = Factory.create()
#USER_AGENT = f.user_agent()
DEFAULT_REQUEST_HEADERS = {
     'Accept' 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8' ,
     'Accept-Encoding' 'gzip, deflate, br' ,
     'Accept-Language' 'zh-CN,zh;q=0.9,en;q=0.8' ,
     'Connection' 'keep-alive' ,
     'User-Agent' 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36' ,
}
ITEM_PIPELINES = {
     #'bookinfo.pipelines.BookinfoStoreMysqlPipeline': 200,
     #'bookinfo.pipelines.BookinfoStoreFilePipeline': 200,
     'bookinfo.pipelines.BookinfoStoreMongoPipeline' : 200,
     'bookinfo.pipelines.BookImgsDLPipeline' : 300,
}
IMAGES_STORE =  '/Users/yuanjicai/Downloads/bookinfo'
IMAGES_EXPIRES = 90
#IMAGES_MIN_HEIGHT = 100
#IMAGES_MIN_WIDTH = 100
#IMAGES_THUMBS = {  
#    'small': (50, 50),  
#    'big': (270, 270),  
#}  
MYSQL_HOST =  '10.18.101.104'
MYSQL_DBNAME =  'book'
MYSQL_USER =  'root'
MYSQL_PASSWD =  '123'
MYSQL_PORT = 3306
MONGODB_HOST =  '10.18.101.104'
MONGODB_PORT = 27017
MONGODB_DB =  'book'
MONGODB_COLLECTION =  'bookinfo'

1)爬取一个Item,将图片的URLs放入image_urls字段

2)从Spider返回的Item,传递到Item Pipeline

3)当Item传递到ImagePipeline,将调用Scrapy 调度器和下载器完成image_urls中的url的调度和下载。ImagePipeline会自动高优先级抓取这些url,于此同时,item会被锁定直到图片抓取完毕才被解锁。

4)图片下载成功结束后,图片下载路径、url和校验和等信息会被填充到images字段中。


cat bookinfo/spiders/bookinfo_spider.py   #实现抓取内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# -*- coding: utf-8 -*-
import  scrapy
import  re
from  bookinfo.items  import  BookinfoItem
class  bookinfoSpider(scrapy.Spider):
     name  =  "bookinfo"
     start_urls  =  "https://book.douban.com/top250"  ]
     def  parse( self ,response):
         yield  scrapy.Request(response.url,callback = self .parse_page)
         for  page_url  in  response.xpath( '//div[@class="paginator"]/a/@href' ).extract():
             yield  scrapy.Request(page_url,callback = self .parse_page)
     def  parse_page( self ,response):
         for  item  in  response.xpath( '//div[@class="article"]/div[1]/table/tr[1]' ):
             bookinfo = BookinfoItem()   #在for循环内实例化在item中定义的各字段,抓取每个item使用一个新的bookinfo空间,相互不影响
             bookinfo[ 'name' ] = item.xpath( "td[2]/div[1]/a/text()" ).extract()[ 0 ].strip()
             bookinfo[ 'price' ] = item.xpath( "td[2]/p/text()" ).extract()[ 0 ].strip().split( "/" )[ - 1 ]
             bookinfo[ 'editor_date' ] = item.xpath( "td[2]/p/text()" ).extract()[ 0 ].strip().split( "/" )[ - 2 ]
             bookinfo[ 'publisher' ] = item.xpath( "td[2]/p/text()" ).extract()[ 0 ].strip().split( "/" )[ - 3 ]
             bookinfo[ 'author' ] = item.xpath( "td[2]/p/text()" ).extract()[ 0 ].strip().split( "/" )[ - 4 ]
             bookinfo[ 'rating' ] = item.xpath( "td[2]/div[2]/span[2]/text()" ).extract()[ 0 ]
             bookinfo[ 'image_urls' ] = item.xpath( "td[1]/a/img/@src" ).extract_first()
             yield  bookinfo

14.png

cat bookinfo/pipelines.py   #由pipeline中定义的类、方法保存抓取的信息及图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# -*- coding: utf-8 -*-
# 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
from  scrapy.pipelines.images  import  ImagesPipeline
from  scrapy.exceptions  import  DropItem
from  scrapy.conf  import  settings    #导入settings 是为了在pipeline中调用setting中定义的各DB参数  
import  scrapy
import  codecs
import  json
import  pymysql
import  pymongo
#通过以下pipeline使用pymysql连接并写入mysql server  
class  BookinfoStoreMysqlPipeline( object ):
     def  __init__( self ):
         pass
     def  dbHandle( self ):
         conn  =  pymysql.connect(host = '10.18.101.104' , db = 'book' , user = 'root' , passwd = '123' , charset = 'utf8' )
         return  conn
     def  process_item( self ,item,spider):
         conn = self .dbHandle()
         cursor = conn.cursor()
         insert_sql  =  'insert into bookinfo(name,author,publisher,url) VALUES (%s,%s,%s,%s)'
         try :
             cursor.execute(insert_sql,(item[ "name" ],item[ "author" ],item[ "publisher" ],item[ "image_urls" ]))
             conn.commit()
         except :
             conn.rollback()
         conn.close()
         return  item
     def  spider_close( self ,spider):
         pass
#通过以下pipeline使用json.dumps形式将返回的数据写入指定json文件中   
class  BookinfoStoreFilePipeline( object ):
     def  __init__( self ):
         self . file = codecs. open ( 'bookinfo.json' , 'w' ,encoding = 'utf-8' )
     def  process_item( self ,item,spider):
         line  =  json.dumps( dict (item),ensure_ascii = False +  "\n"
         self . file .write(line)
         return  item
     def  spider_colse( self ,spider):
         self . file .close()
#通过以下pipeline使用pymongo形式将返回的数据写入mongodb中
class  BookinfoStoreMongoPipeline( object ):
     def  __init__( self ):
         conn = pymongo.MongoClient(settings[ 'MONGODB_HOST' ],settings[ 'MONGODB_PORT' ])
         db = conn[settings[ 'MONGODB_DB' ]]
         self .collection  =  db[settings[ 'MONGODB_COLLECTION' ]]
     def  process_item( self ,item,spider):
         self .collection.insert( dict (item))
         return  item
     def  spider_colse( self ,spider):
         conn.close()
#通过以下pipeline下载抓取过程中存储在image_urls字段的图片  
class  BookImgsDLPipeline(ImagesPipeline):
     default_headers  =  {
         'accept' 'image/webp,image/*,*/*;q=0.8' ,
         'accept-encoding' 'gzip, deflate, sdch, br' ,
         'accept-language' 'zh-CN,zh;q=0.8,en;q=0.6' ,
         'referer' 'https://book.douban.com/top250/' ,
         'user-agent' 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36' ,
     }
     def  get_media_requests( self ,item,info):
         self .default_headers[ 'referer' =  item[ 'image_urls' ]
         yield  scrapy.Request(item[ 'image_urls' ], headers = self .default_headers, meta = { 'bookname' :item[ 'name' ]})
         #将每个bookname附加在meta中传递给下一个函数处理
     def  file_path( self ,request,response = None ,info = None ):
         bookname = request.meta[ 'bookname' ]
         image_guid  =  bookname + '_' + request.url.split( '/' )[ - 1 ]   #自定义保存图片的名称
         filename  =  'full/%s'  %  (image_guid)
         return  filename
     def  item_completed( self ,results,item,info):
         image_paths  =  [ value[ 'path' for  ok, value  in  results  if  ok ]
         if  not  image_paths:
             raise  DropItem( "Item contains no images" )
         item[ 'image_paths' =  image_paths[ 0 ]
         item[ 'images' =  [ value  for  ok, value  in  results  if  ok ]
         return  item

说明:result字典值的格式如下所示:

[(True, {'url': 'https://img3.doubanio.com/mpic/s26012674.jpg', 'path': 'full/b8700497fc0014c87e085747c89476e12162c518.jpg', 'checksum': '4da0defa1ec30229ce724d691f694ad1'})]

Pipline 下载图片时,必须是一个继承ImagesPipeline父类的 类 ,该类必须在setting中调用 ;

ImagePipeline

需要在自定义的ImagePipeline类中重载的方法有:get_media_requests(item, info)和item_completed(results, items, info)

正如工作流程所示,Pipeline将从item中获取图片的URLs并下载它们,所以必须重载get_media_requests,并返回一个Request对象,这些请求对象将被Pipeline处理,当完成下载后,结果将发送到item_completed方法,这些结果为一个二元组的list,每个元祖的包含(success, image_info_or_failure)。 success: boolean值,true表示成功下载 ;如果success=true,image_info_or_error词典包含以下键值对:

     url:原始URL 

     path:本地存储路径 

     checksum:校验码










本文转自 meteor_hy 51CTO博客,原文链接:http://blog.51cto.com/caiyuanji/2043901,如需转载请自行联系原作者
相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。   相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
目录
相关文章
|
4月前
|
数据采集 Python
scrapy异步下载图片
scrapy异步下载图片
36 0
scrapy异步下载图片
|
6月前
|
数据采集 存储 中间件
Amazon图片下载器:利用Scrapy库完成图像下载任务
本文介绍了如何使用Python的Scrapy库编写一个简单的爬虫程序,实现从Amazon网站下载商品图片的功能。Scrapy是一个强大的爬虫框架,提供了许多方便的特性,如选择器、管道、中间件、代理等。本文将重点介绍如何使用Scrapy的图片管道和代理中间件,以提高爬虫的效率和稳定性。
Amazon图片下载器:利用Scrapy库完成图像下载任务
|
数据采集 Python
Python爬虫:scrapy爬取腾讯社招职位信息
Python爬虫:scrapy爬取腾讯社招职位信息
171 0
|
数据采集 关系型数据库 MySQL
五十四、使用Scrapy爬取北京公交信息(将爬取的数据存入Mysql)
五十四、使用Scrapy爬取北京公交信息(将爬取的数据存入Mysql)
五十四、使用Scrapy爬取北京公交信息(将爬取的数据存入Mysql)
|
存储 数据采集 数据可视化
【数据采集】使用scrapy采集天气网、豆瓣数据信息
第三次实验 实验 1 1.1 题目 1.2 思路 1.2.1 发送请求 1.2.2 解析网页 1.2.3 获取结点 1.2.4 数据保存 (单线程) 1.2.4 数据保存 (多线程) 实验 2 2.1 题目 2.2 思路 2.2.1 setting.py 2.2.2 item.py 2.2.3 wt_Spider.py 2.2.4 pipelines.py 实验 3 3.1 题目 3.2 思路 3.2.1 setting.py 3.2.2 item.py 3.2.3 db_Spider.py 3.2.4 pipelines.py 福利
100 0
【数据采集】使用scrapy采集天气网、豆瓣数据信息
|
数据采集 Python
Crawler之Scrapy:Python实现scrapy框架爬虫两个网址下载网页内容信息
Crawler之Scrapy:Python实现scrapy框架爬虫两个网址下载网页内容信息
|
数据采集 JSON 前端开发
13、web爬虫讲解2—Scrapy框架爬虫—Scrapy爬取百度新闻,爬取Ajax动态生成的信息
crapy爬取百度新闻,爬取Ajax动态生成的信息,抓取百度新闻首页的新闻rul地址 有多网站,当你浏览器访问时看到的信息,在html源文件里却找不到,由得信息还是滚动条滚动到对应的位置后才...
2267 0
4、web爬虫,scrapy模块标签选择器下载图片,以及正则匹配标签
标签选择器对象 HtmlXPathSelector()创建标签选择器对象,参数接收response回调的html对象需要导入模块:from scrapy.
858 0
|
数据采集 Python
在Scrapy中如何利用Xpath选择器从HTML中提取目标信息(两种方式)
前一阵子我们介绍了如何启动Scrapy项目以及关于Scrapy爬虫的一些小技巧介绍,没来得及上车的小伙伴可以戳这些文章: 手把手教你如何新建scrapy爬虫框架的第一个项目(上) 手把手教你如何新建scrapy爬虫框架的第一个项目(下) 关于Scrapy爬虫项目运行和调试的小技巧(上篇) 关于Scrapy爬虫项目运行和调试的小技巧(下篇) 今天我们将介绍在Scrapy中如何利用Xpath选择器从HTML中提取目标信息。
1467 0
|
存储 数据采集 Python
scrapy自带文件下载器,实现多层级目录结构的存储
概scrapy既然是一款强大的爬虫框架,自然也实现了图片和文件的下载,FilesPipeline、ImagesPipeline分别是图片和文件的下载器,image也是文件的一种为什么还要单独提供一个image下载器?这是因为图片下载器还提供了一些额外方法:缩略图生成、图片过滤;今天就来介绍这两款特殊的下载器。
1301 0