Python爬虫_案例分析(一)
一、爬取数据
# dang.py
import scrapy
class DangSpider(scrapy.Spider):
name = 'dang'
allowed_domains = ['category.dangdang.com/cp01.01.02.00.00.00.html']
start_urls = ['http://category.dangdang.com/cp01.01.02.00.00.00.html']
def parse(self, response):
# pipelines 下载数据
# items 定义数据结构
# src = '//ul[@id="component_59"]/li//img/@src'
# title = '//ul[@id="component_59"]/li//img/@alt'
# price = '//ul[@id="component_59"]/li//p[@class="price"]/span[1]/text()'
# 所有的seletor对象都可以再次调用xpath方法
li_list = response.xpath('//ul[@id="component_59"]/li')
for li in li_list:
src = li.xpath('.//img/@data-original').extract_first()
# 网站有懒加载机制,故图片路径不是src采用data-original;
# 同时第一张图片没有data-original,要用src
if src:
src = src
else:
src = li.xpath('.//img/@src').extract_first()
title = li.xpath('.//img/@alt').extract_first()
price = li.xpath('.//p[@class="price"]/span[1]/text()').extract_first()
print(src,title,price)
# items.py
# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html
import scrapy
class ScrapyDangdangItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
# 图片
src = scrapy.Field()
# 名字
name = scrapy.Field()
# 价格
price = scrapy.Fiele()
二、管道封装
import scrapy
from scrapy_dangdang.items import ScrapyDangdangItem
class DangSpider(scrapy.Spider):
name = 'dang'
allowed_domains = ['category.dangdang.com/cp01.01.02.00.00.00.html']
start_urls = ['http://category.dangdang.com/cp01.01.02.00.00.00.html']
def parse(self, response):
# pipelines 下载数据
# items 定义数据结构
# src = '//ul[@id="component_59"]/li//img/@src'
# title = '//ul[@id="component_59"]/li//img/@alt'
# price = '//ul[@id="component_59"]/li//p[@class="price"]/span[1]/text()'
# 所有的seletor对象都可以再次调用xpath方法
li_list = response.xpath('//ul[@id="component_59"]/li')
for li in li_list:
src = li.xpath('.//img/@data-original').extract_first()
# 网站有懒加载机制,故图片路径不是src采用data-original;
# 同时第一张图片没有data-original,要用src
if src:
src = src
else:
src = li.xpath('.//img/@src').extract_first()
title = li.xpath('.//img/@alt').extract_first()
price = li.xpath('.//p[@class="price"]/span[1]/text()').extract_first()
book = ScrapyDangdangItem(src=src,title=title,price=price)
# 获取一个book,就将book交给pipelines
yield book
from itemadapter import ItemAdapter
# 如果想要使用管道,则必须在settings中开启管道
class ScrapyDangdangPipeline:
# item是yield后面的book对象
def process_item(self, item, spider):
# 下载数据 这种模式不推荐,每传递一个文件对象就打开一次文件,对文件操作过于频繁
# (1)write方法必须要写一个字符串,而不能是其他对象
# (2)w模式,会每一次对象都打开一次文件,覆盖掉之前的文件内容
with open('book.json','a',encoding='utf-8')as fp:
fp.write(str(item))
return item
上述这种模式不推荐,每传递一个文件对象就打开一次文件,对文件操作过于频繁。
案例改进:
from itemadapter import ItemAdapter
# 如果想要使用管道,则必须在settings中开启管道
class ScrapyDangdangPipeline:
# 在爬虫文件执行前执行
def open_spider(self,spider):
self.fp = open('book.json','w',encoding='utf-8')
# item是yield后面的book对象
def process_item(self, item, spider):
# 下载数据 这种模式不推荐,每传递一个文件对象就打开一次文件,对文件操作过于频繁
# (1)write方法必须要写一个字符串,而不能是其他对象
# (2)w模式,会每一次对象都打开一次文件,覆盖掉之前的文件内容
# with open('book.json','a',encoding='utf-8')as fp:
# fp.write(str(item))
self.fp.write(str(item))
return item
# 在爬虫文件执行完之后执行
def close_spider(self,spider):
self.fp.close()
三、多条管道下载
import urllib.request
# 多条管道开启
# (1) 定义管道类
# (2) 在settings中开启多条管道 : 'scrapy_dangdang.pipelines.DangDangDownloadPipeline':301
class DangDangDownloadPipeline:
def process_item(self, item, spider):
url = 'http:' + item.get('src')
filename = './books/'+ item.get('title') + '.jpg'
urllib.request.urlretrieve(url=url,filename=filename)
return item
四、多页下载
1.dang.py
import scrapy
from scrapy_dangdang.items import ScrapyDangdangItem
class DangSpider(scrapy.Spider):
name = 'dang'
#如果是多页下载,必须要调整allowed_domains的范围,一般情况下只写域名
allowed_domains = ['category.dangdang.com']
start_urls = ['http://category.dangdang.com/cp01.01.02.00.00.00.html']
base_url = 'http://category.dangdang.com/pg'
page = 1
def parse(self, response):
# pipelines 下载数据
# items 定义数据结构
# src = '//ul[@id="component_59"]/li//img/@src'
# title = '//ul[@id="component_59"]/li//img/@alt'
# price = '//ul[@id="component_59"]/li//p[@class="price"]/span[1]/text()'
# 所有的seletor对象都可以再次调用xpath方法
li_list = response.xpath('//ul[@id="component_59"]/li')
for li in li_list:
src = li.xpath('.//img/@data-original').extract_first()
# 网站有懒加载机制,故图片路径不是src采用data-original;
# 同时第一张图片没有data-original,要用src
if src:
src = src
else:
src = li.xpath('.//img/@src').extract_first()
title = li.xpath('.//img/@alt').extract_first()
price = li.xpath('.//p[@class="price"]/span[1]/text()').extract_first()
book = ScrapyDangdangItem(src=src,title=title,price=price)
# 获取一个book,就将book交给pipelines
yield book
# 每一页爬取的业务逻辑全都是一样的,只需要将执行的请求再次调用parse方法
# http://category.dangdang.com/pg2-cp01.01.02.00.00.00.html
# http://category.dangdang.com/pg3-cp01.01.02.00.00.00.html
if self.page < 100 :
self.page = self.page + 1
url = self.base_url + str(self.page) + '-cp01.01.02.00.00.00.html'
# 如何调用parse方法
# scrapy.Request就是scrapy的get请求; url就是请求地址; callback是需要执行的函数,不需要加()
yield scrapy.Request(url=url,callback=self.parse)
2.items.py
import scrapy
class ScrapyDangdangItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
# 图片
src = scrapy.Field()
# 名字
title = scrapy.Field()
# 价格
price = scrapy.Field()
3.settings.py
ITEM_PIPELINES = {
# 管道可以有很多,而管道具有优先级,优先级的范围是1~1000,值越小,优先级越高
'scrapy_dangdang.pipelines.ScrapyDangdangPipeline': 300,
# DangDangDownloadPipeline
'scrapy_dangdang.pipelines.DangDangDownloadPipeline':301
}
4.Pipelines.py
from itemadapter import ItemAdapter
# 如果想要使用管道,则必须在settings中开启管道
class ScrapyDangdangPipeline:
# 在爬虫文件执行前执行
def open_spider(self,spider):
self.fp = open('book.json','w',encoding='utf-8')
# item是yield后面的book对象
def process_item(self, item, spider):
# 下载数据 这种模式不推荐,每传递一个文件对象就打开一次文件,对文件操作过于频繁
# (1)write方法必须要写一个字符串,而不能是其他对象
# (2)w模式,会每一次对象都打开一次文件,覆盖掉之前的文件内容
# with open('book.json','a',encoding='utf-8')as fp:
# fp.write(str(item))
self.fp.write(str(item))
return item
# 在爬虫文件执行完之后执行
def close_spider(self,spider):
self.fp.close()
import urllib.request
# 多条管道开启
# (1) 定义管道类
# (2) 在settings中开启多条管道 : 'scrapy_dangdang.pipelines.DangDangDownloadPipeline':301
class DangDangDownloadPipeline:
def process_item(self, item, spider):
url = 'http:' + item.get('src')
filename = './books/'+ item.get('title') + '.jpg'
urllib.request.urlretrieve(url=url,filename=filename)
return item