• 使用Scrapy爬取图书网站信息


    重难点:使用scrapy获取的数值是unicode类型,保存到json文件时需要特别注意处理一下,具体请参考链接:https://www.cnblogs.com/sanduzxcvbnm/p/10309401.html

    稍加改造也能保存到csv文件中

    网址:https://sobooks.net/

    1.网站分析

    该图书网站的网址或者是https://sobooks.net/,或者是https://sobooks.cc/,本文以前者为例

    首先看到的截止到当前时间(2019-01-23)共有172页,点击第二页,会发现网址变成:https://sobooks.net/page/2,点击第三页网址变成https://sobooks.net/page/3,不难想象,若是网址是https://sobooks.net/page/1,出现的页面是否跟https://sobooks.net/一样呢,结果是一样的,然后访问手动输入地址https://sobooks.net/page/172访问,会发现直接到最后一页了,顺便统计一下,最后一页有6本图书,前171页每页有24本图书,合计图书有171*24+6=4110本

    这样一来就可以使用循环的方式来遍历每页的图书了

    2.进入到图书详情页面,比如:https://sobooks.net/books/11582.html,会发现页面提供的有百度云网盘和城通网盘的下载地址,不过有些图书页面只提供百度云网盘的地址,所以本文只获取百度云网盘的地址。

    页面上提供的是一个跳转链接地址,经过分析发现百度云网盘在=号后面,可以先提取出href的值然后使用split('=')切割获取后者即可得到百度云网盘地址

    另外还需要在当前页面输入验证码提交后才能获取到百度云网盘的提取码。通过查看源码可知:

    采用post的方式将验证码(2018919)提交到当前页面进而获得百度云提取码

    一般的做法是进入到图书详情页面后再使用post方式提交验证码到当前页面获取提取码,不过这两步可以合成一步操作,就是采用post提交数据的方式进入到图书详情页面,这样一来,既进入了图书详情页面,同时页面上直接显示的就有提取码。不过scrapy默认使用的get方式,所以需要修改scrapy的中的相关方法;

    3.进入到图书详情页面后接下来就按照正常流程输出需要的字段信息,全部采用css的方式(浏览器调试工具:css选择器),同时辅助使用表达式。

    4.最后把图书信息保存到json文件中

    5.源码文件

    settings.py

    增加如下内容,其余保持不变

    ITEM_PIPELINES = {
        'sobooks.pipelines.JsonWithEncodingPipeline': 200,
    }

    items.py

    import scrapy
    
    class SobooksItem(scrapy.Item):
        # define the fields for your item here like:
        # name = scrapy.Field()
    
        url = scrapy.Field()
    
        title = scrapy.Field()
        classification = scrapy.Field()
        author = scrapy.Field()
        down_bd_url = scrapy.Field()
        down_bd_code = scrapy.Field()
        down_ct_url = scrapy.Field()

    pipelines.py

    import codecs
    import json
    
    class JsonWithEncodingPipeline(object):
        """
        命令行里输出的是unicode,但是保存到json文件中是中文
        """
    
        def __init__(self):
            self.file = codecs.open('items.json', 'w', encoding='utf-8')
    
        def process_item(self, item, spider):
            line = json.dumps(dict(item), ensure_ascii=False) + "
    "
            # print('图书%s保存成功' % (item['title'].encode('utf-8')))
            self.file.write(line)
            return item
    
        def close_spider(self, spider):
            self.file.close()

    sobook.py

    # -*- coding: utf-8 -*-
    
    import re
    import scrapy
    from sobooks.items import SobooksItem
    
    
    class SobookSpider(scrapy.Spider):
        """
        爬虫思路梳理
        开始时的想法是使用get方式进入到书籍详情页面,然后再使用post方式给本页发送验证码获得百度云网盘提取密码,这样操作步骤较为繁琐
        倒不如直接使用post方式给本页发送验证码,从而将上面的两步合成一步
        """
    
        name = 'sobook'
        allowed_domains = ['sobooks.net']
        base_url = 'https://sobooks.net/page/'
    
        pages = list(range(1, 173))
    
        def start_requests(self):
            # 遍历循环图书索引页
            for page in self.pages:
                url = self.base_url + str(page)
                # print('请求第%s页' % (page))
                yield scrapy.Request(url=url, callback=self.parse)
    
        def parse(self, response):
            # 使用css选择器
            res = response.css('#cardslist div.card').extract()
            for card in res:
                # 获取图书详情页链接
                pattern = re.compile('<h3>.*?<a href="(.*?)".*?>.*?</a>.*?</h3>', re.S)
                url = re.findall(pattern, card)
    
                # print('Get Book URI %s' % (url[0]))
                # 使用post方式提交验证码进入图书详情页面
                yield scrapy.FormRequest(url=url[0], formdata={'e_secret_key': '2018919'},
                                         callback=self.detail_parse)
    
        def detail_parse(self, response):
    
            title = response.css('.article-title > a:nth-child(1)::text').extract_first()
            classification = response.css('#mute-category > a:nth-child(2)::text').extract_first()
            author = response.css('span.muted:nth-child(2) > a:nth-child(2)::text').extract_first()
            # 若是需要城通网盘地址,参考百度云网盘地址写法(CSS选择器)
            down_bd_url = response.css(
                '.dltable > tbody:nth-child(1) > tr:nth-child(3) > td:nth-child(1) > a:nth-child(2)::attr(href)').extract_first().split(
                '=')[1]
            down_bd_code = response.css('.e-secret > strong:nth-child(1)::text').extract_first()
    
            item = SobooksItem()
            item['title'] = title
            item['classification'] = classification
            item['author'] = author
            item['down_bd_url'] = down_bd_url
            item['down_bd_code'] = down_bd_code
    
            yield item

    6.效果:

    通过查看json文件,发现有4098本图书数据,跟之前计算的4110本差2本,这2本具体是啥懒得找了,就先这样吧

    通过分析json文件中的地址,应该取的是百度云网盘的地址,但是部分地址是城通网盘的,通过搜索图书查看发现该图书并未提供百度云网盘地址,只提供城通网盘地址

    源码下载地址:https://files.cnblogs.com/files/sanduzxcvbnm/sobooks.7z

  • 相关阅读:
    spring filter and interceptor
    spring 与 swagger 2 的整合
    spring 异步操作
    图片延迟加载 jquery,lazyload.js 调用的demo
    一、Spring的第一个课时
    线程的基本了解
    HTTPS/HTTP监听常见问题
    Leetcode 118 杨辉三角
    HashSet的源码解释
    HashMap源码理解
  • 原文地址:https://www.cnblogs.com/sanduzxcvbnm/p/10309844.html
Copyright © 2020-2023  润新知