Scrapy_redis爬虫案例-京东图书

鳄鱼君

发表文章数:531

Vieu四代商业主题

高扩展、安全、稳定、响应式布局多功能模板。

¥69 现在购买
首页 » Python教程 » Scrapy_redis爬虫案例-京东图书

本文会通过演示京东图书爬虫,来深刻了解scrapy_redis的使用,京东图书跟苏宁图书一样,都是包含大分类和小分类,我们把所有的信息都存储在一个item字典中,所以还需要deepcopy,具体请看详细内容。

京东图书目前分类样式如图,我们不要看最左边的分类,因为补全,我们查看隐藏的标签,分析写XPATH代码,需要注意在响应中是否真的存在这样的标签。

Scrapy_redis爬虫案例-京东图书

首先创建爬虫项目,然后创建爬虫文件:

scrapy startproject jd
cd jd
scrapy genspider jd jd.com

我们可以看到图片中的html标签是隐藏的,所以在源代码中是没有的,我们这样的思路通常不会提取到任何内容。确实,京东做了相关的反扒测试,html源码中没有我们想要的信息。经过一番查找,发现数据是通过json接口:https://lapi.jd.com/pool?body={“pid”:”0101947″}&source=book,这个接口中已经包含所有的分类信息,大分类和小分类,各自的链接。这到减少了写XPATH的代码,我们把这个接口当做起始的url,顺便添加到允许的域名内.

参数中有个重要的内容pid,经观察发现,不同的值对应不同的分类,那么就需要提取这个数字,这样才能获取到所有的分类:

Scrapy_redis爬虫案例-京东图书

但是在源码中是不存在这个值的,所以还需要找到这个数据是如何生成的,查找发现一个js文件:https://misc.360buyimg.com/channel/bookhome/3.0.0/widget/category/category.js在浏览器中打开,会发现是编码过的,使用解码工具查看,由于是js文件肯定有干扰,我们直接看标签,里面有li标签和其它的标签,这才是重点,发现这个正是我们在上面图片中寻找的li标签,数量都是18个,完美吻合,需要注意查看的时候去掉js代码,只看我们的标签,不然不会是18个,有干扰内容。那么一切都很好办了。/p>

由于我们只需要提取一次这个js文件,所以我们不关心它的url是如何构造的,直接抓取即可,那么我们使用正则提取对应的pid值,但是最终发现,XXX所有的图书分类:https://book.jd.com/booksort.html在这个url就可找到,源代码中所存在所有的数据,我还找半天,只怪我太年轻了。一些就变得简单起来,代码参考:

# -*- coding: utf-8 -*-
import scrapy
import json
from copy import deepcopy
from urllib.parse import urljoin

class BookjdSpider(scrapy.Spider):
    name = 'bookjd'
    allowed_domains = ['jd.com','p.3.cn']#注意添加价格的url地址
    start_urls = ['https://book.jd.com/booksort.html']

    def parse(self, response):
        dt_list=response.xpath('//div[@class="mc"]/dl/dt')
        for dt in dt_list:
            item={}
            #大分类
            item['b_cate']=dt.xpath('./a/text()').extract_first()
            dd_list=dt.xpath('./following-sibling::dd[1]/em') #取dt的平级标签
            for dd in dd_list:
                #小分类
                item['s_cate']=dd.xpath('./a/text()').extract_first()
                item['s_href']='https:'+dd.xpath('./a/@href').extract_first()
                #大分类和小分类公用一个item字典,避免数据覆盖,使用deepcopy
                yield scrapy.Request(
                    item['s_href'],
                    callback=self.parse_booklist,
                    meta={'item':deepcopy(item)}
                )
    #解析图书的列表页
    def parse_booklist(self,response):
        item=response.meta['item']
        li_list=response.xpath('//div[@id="plist"]/ul/li')
        for li in li_list:
            item['book_img']=li.xpath('.//div[@class="p-img"]/a/img/@src').extract_first()
            #图书图片的url地址存在多个属性中src和data-lazy-img
            if not item['book_img']:
                item['book_img']=li.xpath('.//div[@class="p-img"]/a/img/@data-lazy-img').extract_first()
            #书的作者可能存在多个,我们可以在
            item['book_name']=li.xpath('.//div[@class="p-name"]/a/em/text()').extract()
            item['book_shop']=li.xpath('.//div[@class="p-shopnum"]/span/text()').extract()
            item['book_sku']=li.xpath('.//div[@class="p-operate"]/a/@data-sku').extract_first()
            #价格需要通过json接口,我们构造url地址,使用parse_detail_price函数提取价格
            yield scrapy.Request(
                'https://p.3.cn/prices/mgets?skuIds=J_{}'.format(item['book_sku']),
                callback=self.parse_detail_price,
                meta={'item':item},
            )
        #列表页翻页
        next_url=response.xpath('//a[@class="pn-next"]/@href').extract_first()
        if next_url is not None:
            next_url=urljoin(response.url,next_url)
            yield scrapy.Request(
                next_url,callback=self.parse_booklist,
                meta={'item':item}
            )
    def parse_detail_price(self,response):
        item=response.meta['item']
        html=json.loads(response.body.decode())
        item['book_price']=html[0]['p']
        print(item)

为了减少文章的篇幅,代码全放上了,基本都是每写一步验证一下,避免出错。那么我们在settings中添加以下代码,即可实现断点续爬:

# -*- coding: utf-8 -*-


BOT_NAME = 'jd'

SPIDER_MODULES = ['jd.spiders']
NEWSPIDER_MODULE = 'jd.spiders'
LOG_LEVEL='WARNING'

USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0'

ROBOTSTXT_OBEY = False
ITEM_PIPELINES = {
   'jd.pipelines.JdPipeline': 300,
   'scrapy_redis.pipelines.RedisPipeline':400,
}
#指定哪个去重方法结合request对象去重
DUPEFILTER_CLASS='scrapy_redis.dupefilter.RFPDupeFilter'
#指定scheduler队列
SCHEDULER='scrapy_redis.scheduler.Scheduler'
#队列中的内容是否持久保存,为False的时候,关闭redis的同时会清空redis数据
SCHEDULER_PERSIST=True

REDIS_URL='redis://127.0.0.1:6379'

我去掉了一些注释,然后需要开启redis服务端和客户端,查看是否成功,需要注意我们没有使用item,所以在redis数据库中是不存在items键值的。为了演示结果,我是直接打印出来,可自行修改。scrapy_redis也可以实现分布式爬虫,那么可参考文章:scrapy_redis通过RedisSpider类实现分布式爬虫

未经允许不得转载:作者:鳄鱼君, 转载或复制请以 超链接形式 并注明出处 鳄鱼君
原文地址:《Scrapy_redis爬虫案例-京东图书》 发布于2020-03-20

分享到:
赞(3) 赏杯咖啡

评论 抢沙发

1 + 8 =


文章对你有帮助可赏作者一杯咖啡

支付宝扫一扫打赏

微信扫一扫打赏

Vieu4.6主题
专业打造轻量级个人企业风格博客主题!专注于前端开发,全站响应式布局自适应模板。
切换注册

登录

忘记密码 ?

您也可以使用第三方帐号快捷登录

Q Q 登 录
微 博 登 录
切换登录

注册