scrapy:当当网案例
1. 创建爬虫项目
2. 创建爬虫文件
3. 运行测试是否目标网站反爬
测试ok没反爬
4. 定义数据结构&yield&实现爬虫&管道封装
import scrapy
from scrapy_dangdang_4.items import ScrapyDangdang4Item # 这里编译报错没有关系,下面调用的地方不报错就行
class DangSpider(scrapy.Spider):
name = "dang"
allowed_domains = ['http://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):
# print('=================') # 先打印一下,若没输出打印则反爬了,需要特殊处理
# pipelines.py 下载数据
# items.py 定义数据结构
# src = //ul[@id="component_59"]/li//img/@src
# alt = //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是可以使用的,其他图片的地址是data-original(加载到之后会自动赋值给src)
src = li.xpath('.//img/@data-original').extract_first()
if src:
src = src
else: # src==None (第一张图片img没有data-original属性)
src = li.xpath('.//img/@src').extract_first()
name = li.xpath('.//img/@alt').extract_first()
price = li.xpath('.//p[@class="price"]/span[1]/text()').extract_first()
book = ScrapyDangdang4Item(src=src, name=name, price=price)
# 每获取到一个book就将book交给pipelines用于下载
yield book
# 带有 yield 的函数不再是一个普通函数,而是一个生成器generator,可用于迭代
# yield就是 return 返回一个值,并且记住这个返回的位置,下次迭代就从这个位置后(下一行)开始
5. 优化管道封装
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
# useful for handling different item types with a single interface
from itemadapter import ItemAdapter
# 如果想使用管道的话 那么就必须在settings中开启管道
class ScrapyDangdang4Pipeline:
# 在爬虫文件开始之前执行的方法
def open_spider(self, spider):
print("++++++++++++++++++++++++++++++++++++++++++++++++")
self.fp = open('book.json', 'w', encoding='utf-8') # 这里可以用'w',因为打开后在爬虫结束完之前没有关闭
def process_item(self, item, spider): # item即parse()中yield传过来的book对象
'''
# (1) write方法必须要写一个字符串 而不能是其他的类型,比如对象item
# (2) 'w'模式 会每一个对象都打开一次文件 覆盖之前的内容;所以要用'a'追加模式
with open('book.json', 'a', encoding='utf-8') as fp:
# ctrl+alt+L 格式化代码格式化json文件
fp.write(str(item))
'''
# 以上这种模式不推荐,因为每传递过来一个对象,那么就打开一次文件,对文件的操作过于频繁
self.fp.write(str(item))
return item
# 在爬虫文件执行完之后执行的方法
def close_spider(self, spider):
print("--------------------------------------------------")
self.fp.close()
6. 开启多管道下载
# (1) 定义管道类 DangDangDownloadPipeline
# (2) 在settings中开启管道 'scrapy_dangdang_4.pipelines.DangDangDownloadPipeline': 301
scrapy crawl dang
7. 多页下载
import scrapy
from scrapy_dangdang_4.items import ScrapyDangdang4Item # 这里编译报错没有关系,下面调用的地方不报错就行
class DangSpider(scrapy.Spider):
name = "dang"
# allowed_domains = ['http://category.dangdang.com/cp01.01.02.00.00.00.html']
# 如果是多页下载的话 那么必须要调整的是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):
# print('=================') # 先打印一下,若没输出打印则反爬了,需要特殊处理
# pipelines.py 下载数据
# items.py 定义数据结构
# src = //ul[@id="component_59"]/li//img/@src
# alt = //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是可以使用的,其他图片的地址是data-original(加载到之后会自动赋值给src)
src = li.xpath('.//img/@data-original').extract_first()
if src:
src = src
else: # src==None (第一张图片img没有data-original属性)
src = li.xpath('.//img/@src').extract_first()
name = li.xpath('.//img/@alt').extract_first()
price = li.xpath('.//p[@class="price"]/span[1]/text()').extract_first()
book = ScrapyDangdang4Item(src=src, name=name, price=price)
# 每获取到一个book就将book交给pipelines用于下载
yield book
# 带有 yield 的函数不再是一个普通函数,而是一个生成器generator,可用于迭代
# yield就是 return 返回一个值,并且记住这个返回的位置,下次迭代就从这个位置后(下一行)开始
'''
多页下载:
每一页的爬取的业务逻辑全都是一样的,所以我们只需要将执行的那个页的请求再次调用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
http://category.dangdang.com/pg4-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就是scrpay的get请求
# url就是请求地址
# callback是你要执行的那个函数 注意不需要加()
yield scrapy.Request(url=url, callback=self.parse)
scrapy crawl dang
耗时太长,控制台ctrl+c暂停爬虫程序了,只要多于一页60条就成功了;测试完后要删掉数据,因为上传git时数据量较大