1.需求了解
需求:抓取亚马逊图书的信息
目标:抓取亚马逊图书信息, 有图书的名字、封面图片地址、图书url地址、作者、出版社、出版时间、价格、图书所属大分类、图书所属小的分类、分类的url地址
url:https://www.amazon.cn/图书/b/ref=sd_allcat_books_l1?ie=UTF8&node=658390051
创建文件
scrapy startproject book
cd book
scrapy genspider -t crawl amazon amazon.cn
2. 思路分析
1. 确定rule中的规则
可以通过连接提取器中的restrict_xpath来实现url地址的,不需要定位到具体的url地址字符串,定位到准确的标签位置即可
注意:定位到的标签中不能包含不相关的url,否则请求不相关的地址后,数据提取会报错
通过分析大分类和小分类的url地址,发现他们的规则相同,即一个Rule可以实现从大分类到小分类的到列表页的过程
大分类的url地址,用’//[@id=“leftNav”]/ul[1]/ul/div/li’提取
小分类的url地址,用’//[@id=“leftNav”]/ul[1]/ul/div/li’提取
列表页的url位置,用’//*[@id=“pagn”]‘提取
进入详情页翻页的url地址位置,用’//div[@class=“a-row”]/div[1]/a’提取
设置Relu抓取这些位置的url
rules = (
Rule(LinkExtractor(restrict_xpaths=r'//*[@id="leftNav"]/ul[1]/ul/div/li'), follow=True),
Rule(LinkExtractor(restrict_xpaths=r'//*[@id="pagn"]'), follow=True),
Rule(LinkExtractor(restrict_xpaths=r'//div[@class="a-row"]/div[1]/a'), callback='parse_item', follow=True),
)
全部写完后:
# -*- coding: utf-8 -*-
import re
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
class AmazonSpider(CrawlSpider):
name = 'amazon'
allowed_domains = ['amazon.cn']
start_urls = ['https://www.amazon.cn/%E5%9B%BE%E4%B9%A6/b/ref=sd_allcat_books_l1?ie=UTF8&node=658390051']
rules = (
Rule(LinkExtractor(restrict_xpaths=r'//*[@id="leftNav"]/ul[1]/ul/div/li'), follow=True),
Rule(LinkExtractor(restrict_xpaths=r'//*[@id="pagn"]'), follow=True),
Rule(LinkExtractor(restrict_xpaths=r'//div[@class="a-row"]/div[1]/a'), callback='parse_item', follow=True),
)
def parse_item(self, response):
"""提取图书的信息"""
# 名字、封面图片地址、图书url地址、作者、出版社、出版时间、价格、图书所属大分类、图书所属小的分类、分类的url地址
item = {}
name = response.xpath('//*[@id="productTitle"]/text()').extract_first()
if name:
# 纸质书
item['name'] = name
else:
# 电子书
item['name'] = response.xpath('//*[@id="ebooksProductTitle"]/text()').extract_first()
item['url'] = response.url
item['author'] = response.xpath('//*[@id="bylineInfo"]/span[1]/a/text()').extract_first()
# 价格平装,电子版虽然不一样,但是class属性都包含 a-color-price , 第一个就是该书的价格
item['price'] = response.xpath('//span[contains(@class,"a-color-price")]/text()').extract_first().strip()
# 获取分类信息
a_s = response.xpath('//*[@id="wayfinding-breadcrumbs_feature_div"]//a')
# 由于从不同目录进入, 获取到的分类不同, 所以需要对多种情况进行判断
if len(a_s) >= 1:
item['b_category_name'] = a_s[0].xpath('./text()').extract_first().strip()
item['b_category_url'] = response.urljoin(a_s[0].xpath('./@href').extract_first())
if len(a_s) >= 2:
item['m_category_name'] = a_s[1].xpath('./text()').extract_first().strip()
item['m_category_url'] = response.urljoin(a_s[1].xpath('./@href').extract_first())
if len(a_s) >= 3:
item['s_category_name'] = a_s[2].xpath('./text()').extract_first().strip()
item['s_category_url'] = response.urljoin(a_s[2].xpath('./@href').extract_first())
# 使用正则提取出版社 和 出版时间, 可以做到电子书与纸质书统一
publisher = re.findall('<li><b>出版社:</b>(.*?)</li>', response.text)
# 有个别图书是没有出版社信息的
if len(publisher) != 0:
item['publisher'] = publisher[0]
item['published_date'] = re.findall('\((.*?)\)', publisher[0])[0]
yield item
然后修改start_url为redis_key
继承的类改为rediscrawlspider
class AmazonSpider(RedisCrawlSpider):
name = 'amazon'
allowed_domains = ['amazon.cn']
# start_urls = ['https://www.amazon.cn/%E5%9B%BE%E4%B9%A6/b/ref=sd_allcat_books_l1?ie=UTF8&node=658390051']
redis_key = 'amazon:start_urls'
在脚本中写入url,启动redis数据库后写入数据
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import redis
# 将start_url 存储到redis中的redis_key中,让爬虫去爬取
redis_Host = "127.0.0.1"
redis_key = 'amazon:start_urls'
# 创建redis数据库连接
rediscli = redis.Redis(host=redis_Host, port=6379, db="0")
# 先将redis中的requests全部清空
flushdbRes = rediscli.flushdb()
print("flushdbRes = {}".format(flushdbRes))
rediscli.lpush(redis_key, "https://www.amazon.cn/%E5%9B%BE%E4%B9%A6/b/ref=sd_allcat_books_l1?ie=UTF8&node=658390051")
最后在settings中写入redis的配置项
# Scrapy_Redis配置信息
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
SCHEDULER_PERSIST = True
# 配置使用Redis来存储爬取到的数据, 如果不需要使用Redis存储可以不配置
ITEM_PIPELINES = {
'scrapy_redis.pipelines.RedisPipeline': 400,
}
# Redis数据库配置
REDIS_URL = "redis://127.0.0.1:6379"
然后就可以启动项目了