0


Scrapy爬虫框架案例学习之五(爬取京东图书信息通过selenium中间件技术)

1、网站分析

1.1 加载的首页

上图是首页源码的元素分析,如果能拿到这个网页源码,包含了大类小说和小类中国当代小说等的链接,然后再放到解析函数去解析即可。但是这个页面源码通过request请求是获取不到的。

找到大类小类的数据也是通过JSON动态加载的。

这里面的数据并没有相关的详情链接,因此没有办法使用。这里通过scrapy爬虫中间件技术来使用selenium获取pagesource,这个页面源代码就是和第一张图片内的elements数据一样了。

1.2 我们需要从大类链接中再次遍历小类链接,获得小类链接的解析,从详情页中提取数据,详情页还需要翻页。大类大概有50多个,每个小类大约10个,小类大约100页,每页60本图书介绍,这样如果都爬完,可以获得5010100*60=3000000条信息,我这只是学习用,因此,这边放了个切片,比如:for big_node in big_node_list[0:1]:这个后面的[0:1]只是获取第一个大类节点的链接,如果把切片去掉,就是获取全部大类的链接。

2 selenium

Selenium是一个用于Web应用程序测试的工具,用Python语言可以自动化操作浏览器,模拟用户的行为,但是效率确实相对接口来说有些低,但是我们这里只需要运行一次拿到全部链接即可。根据浏览器的不同和不同的版本,下载相应的驱动。我用的是谷歌,CNPM Binaries Mirror

3 中间件文件内容

from scrapy import signals
import time
from selenium import webdriver
# useful for handling different item types with a single interface
from itemadapter import is_item, ItemAdapter
from scrapy.http import HtmlResponse

class SelenimuMiddleWare(object):
    def process_request(self,request,spider):
        url =request.url
        #print(url)

        options = webdriver.ChromeOptions()
        options.add_experimental_option('useAutomationExtension', False)
        options.add_experimental_option('excludeSwitches', ['enable-automation'])
        options.add_argument('--headless')#无头浏览器
        options.add_argument('--disable-gpu')

        driver = webdriver.Chrome(options=options)
        driver.execute_cdp_cmd(
            "Page.addScriptToEvaluateOnNewDocument",
            {"source":"""
            Object.defineProperty(navigator,'webdriver',{
              get: () => undefined
            })
          """})

        driver.get(url)
        time.sleep(5)
        data = driver.page_source
        
        driver.close()
        res = HtmlResponse(url=url,body = data,encoding='utf-8',request = request)
        return res

(1)、options是启动浏览器的启动参数,1-2行,是消除浏览器上受自动化测试软件的控制,3-4行是无头模式,有时不想让过程显示出来,driver.execute_cdp_cmd是把浏览器一个属性为webdriver取消定义,这样不让服务器发现是自动化软件控制,不然不给你返回内容。

(2)、这些都是固定格式,可以封装为其他函数放到外面,在中间件里引用也是可以的。

4、爬虫页面文件

import scrapy
from jdbooks.items import JdbooksItem

#导入分布式爬虫类,
#redis-server.exe redis.windows.conf
#scrapy runspider jd.py
#lpush myjd https://book.jd.com/booksort.html
from scrapy_redis.spiders import RedisCrawlSpider

next_page = 1
i = 0

class JdSpider(scrapy.Spider):
    name = "jd"
    #设置redis_key

    # redis_key = 'myjd'
    allowed_domains = ["jd.com"]
    start_urls = ["https://book.jd.com/booksort.html"]

    def __init__(self):
        # domain = kwargs.pop('domain','')
        # self.allowed_domains = list(filter(None,domain.split(',')))
        # super(JdSpider,self).__init__(*args,**kwargs)

        self.table_name = 'jdbooks'
        self.table_fields = ['big_category','big_category_link','small_category','small_category_link',
        'book_point','book_name','author','link','press','pub_date','descinfo','price']

    def parse(self, response):
        big_node_list =response.xpath('//*[@id="booksort"]/div[2]/dl/dt/a')
        print(len(big_node_list))

        for big_node in big_node_list[0:1]:
            big_category = big_node.xpath('./text()').extract_first()
            big_category_link = response.urljoin(big_node.xpath('./@href').extract_first())
            small_node_list  = big_node.xpath('../following-sibling::dd[1]/em/a')
            item = JdbooksItem()
            item['table_fields'] = self.table_fields
            item['table_name'] = self.table_name

            for small_node in small_node_list[0:1]:
                
                item['big_category'] = big_category
                item['big_category_link'] = big_category_link
                item['small_category'] = small_node.xpath('./text()').extract_first()
                item['small_category_link'] = response.urljoin(small_node.xpath('./@href').extract_first())

                #模拟点击小分类链接到详情页再去取数据
                yield scrapy.Request(
                    url = item['small_category_link'],
                    callback = self.parse_detail,
                    meta={'item':item}
                    )

    def parse_detail(self, response):
        item = response.meta['item']
        book_lists = response.xpath('//*[@id="J_goodsList"]/ul/li/div')
        for book_list in book_lists:
            item['book_point'] = book_list.xpath('./div[3]/a/em/text()').extract_first().strip()
            string = str(item['book_point'])
            if '】' in string:
                item['book_name']  = string.split('】')[1].split('(')[0].split(' ')[0]
            else:
                item['book_name'] = string.split('(')[0].split(' ')[0]

            item['author']  = book_list.xpath('./div[4]/span[1]/a/text()').extract_first()
            item['link'] = response.urljoin(book_list.xpath('./div[3]/a/@href').extract_first().strip())
            item['press']  = book_list.xpath('./div[4]/span[2]/a/text()').extract_first()
            item['pub_date'] = book_list.xpath('./div[4]/span[3]/text()').extract_first()
            item['descinfo'] = book_list.xpath('./div[3]/a/@title').extract_first().strip()
            item['price'] = book_list.xpath('./div[2]/strong/i/text()').extract_first()
            #print(item)
            yield item

        # #模拟翻页
        flag = response.xpath('//*[@id="J_bottomPage"]/span[1]/a[last()]/@href').extract_first()
        print('================================================================')
               
        # https://list.jd.com/list.html?cat=1713%2C3258%2C3297&page=3&s=57&click=0
        # https://list.jd.com/list.html?cat=1713%2C3258%2C3297&page=5&s=117&click=0
        # https://list.jd.com/list.html?cat=1713%2C3258%2C3297&page=7&s=177&click=0
        # https://list.jd.com/list.html?cat=1713%2C3258%2C3297&page=9&s=237&click=0

        global next_page , i
        next_page = next_page + 2
        i= i+1
        if flag != '':
            num = 60*i -3
            cat = item['small_category_link'].split('.com/')[1].split('.')[0].replace('-','%2C')
            next_url = 'https://list.jd.com/list.html?cat={}&page={}&s={}&click=0'.format(cat,next_page,num)
            print(next_url)
            yield scrapy.Request(
                url=next_url,              
                callback=self.parse_detail,
                meta={'item':item}
            )

模拟翻页的时候注意链接的变化规律,一共有3个变量需要传递,其中cat是小说分类里面的小类,从item里面获得,需要处理下。还有2个页面的数字,注意下变化的规律即可。

5、数据写入Mysql即可。

本案例仅供学习使用。

标签: scrapy 爬虫 学习

本文转载自: https://blog.csdn.net/u010152658/article/details/131758470
版权归原作者 u010152658 所有, 如有侵权,请联系我们删除。

“Scrapy爬虫框架案例学习之五(爬取京东图书信息通过selenium中间件技术)”的评论:

还没有评论