前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >爬虫 | 百行代码爬取14.5W条豆瓣图书信息

爬虫 | 百行代码爬取14.5W条豆瓣图书信息

作者头像
咸鱼学Python
发布2019-10-09 15:01:38
4940
发布2019-10-09 15:01:38
举报
文章被收录于专栏:咸鱼学Python
前言

先上一波爬取的结果:

数据库中部分截图

实战

引入类库

代码语言:javascript
复制
import requests
from bs4 import BeautifulSoup
from requests.exceptions import RequestException
from urllib.parse import urlencode
import pymongo
import numpy as np
import time
from faker import Faker

分析页面请求

分析目标页面

打开开发者模式,查看链接

点击任意标签,分析页面请求 分别请求不同的标签页面,分析请求链接,可以发现如下规律:

代码语言:javascript
复制
tag_url = 'https://book.douban.com' + 标签页中a标签括起来的内容

由此,我们可以构建以下代码,以获取标签页面所有标签链接:

代码语言:javascript
复制
# 解析总标签页面,并拼接获得所有标签页页面链接
def splice_tags_indexhtml(html):
    url = 'https://book.douban.com'
    book_tags = []
    tags_url = []
    soup = BeautifulSoup(html, 'lxml')
    tagurl_lists = soup.select('#content > div > div.article > div > div > table > tbody > tr > td > a')
    for tag_url in tagurl_lists:
        # 获取全部标签的a标签内容,并拼接到一起
        book_tags += [tag_url.attrs["href"]]
    for book_tag in book_tags:
        tags_url.append([url + book_tag])
    return tags_url

我们进入单个标签页面,分析图书列表页面,解析我们需要存储的字段 我们通过bs4解析我们需要的字段,如:出版时间,作者/译者,豆瓣评分,售价,评价人数等。

代码语言:javascript
复制
# 解析单个tag页面下单页的信息
def parse_tag_page(html):
    try:
        soup = BeautifulSoup(html,"lxml")
        tag_name = soup.select('title')[0].get_text().strip()
        list_soup = soup.find('ul', {'class': 'subject-list'})
        if list_soup == None:
            print('获取信息列表失败')
        else:
            for book_info in list_soup.findAll('div', {'class': 'info'}):
                # 书名
                title = book_info.find('a').get('title').strip()
                # 评价人数
                people_num = book_info.find('span', {'class': 'pl'}).get_text().strip()
                # 出版信息,作者
                pub = book_info.find('div', {'class': 'pub'}).get_text().strip()
                pub_list = pub.split('/')
                try:
                    author_info = '作者/译者: ' + '/'.join(pub_list[0:-3])
                except:
                    author_info = '作者/译者: 暂无'
                try:
                    pub_info = '出版信息: ' + '/'.join(pub_list[-3:-1])
                except:
                    pub_info = '出版信息: 暂无'
                try:
                    price_info = '价格: ' + '/'.join(pub_list[-1:])
                except:
                    price_info = '价格: 暂无'
                try:
                    rating_num= book_info.find('span', {'class': 'rating_nums'}).get_text().strip()
                except:
                    rating_num = '0.0'
                book_data = {
                    'title': title,
                    'people_num': people_num,
                    'author_info': author_info,
                    'pub_info': pub_info,
                    'price_info': price_info,
                    'rating_num': rating_num
                }
                # return book_data
                if book_data:
                    save_to_mongo(book_data,tag_name)
    except:
        print('解析错误')
        return None

到这里,我们已经可以获取到单个tag下单页的图书信息,这个时候我们只需要加入翻页功能就可以实现单个tag下所有图书的信息爬取。

点击下一页,分析页面请求 可以看到页面多了start和type两个参数,同时start参数是从0开始并以20的偏移量递增的,我们按照这个规律可以构建一个生成器以生成start参数。 从文章的第一张图,可以看出不同的tag页有不同的数量的图书,那页面数量也不尽相同,这时应该如何构建生成器? 这个时候我们发现所有的tag在第50页之后都请求不出信息了,所以我们只需构建前50页的页面链接即可,第51页显示如下:

第51页的显示结果

代码语言:javascript
复制
# 请求tag下的每个页面
def get_tag_page(tag_url,page):
        formdata = {
            'start': page,
            'type': 'T'
        }
        url = tag_url[0]+'?'+ urlencode(formdata)
        try:
            reponse = requests.get(url, headers=headers)
            if reponse.status_code == 200:
                return reponse.text
            return None
        except RequestException:
            print('请求列表页错误')
            return None

反反爬 豆瓣的反爬简单粗暴,直接封IP,为了爬虫的健壮,可以使用代理或者随机Header+随机时延的方式,随机时延可以设置为30到40之间,不过这样大大影响了爬取速率,如果需要快速爬取可以采用代理+多线程+随机Header+随机时延这样就能避过反爬又能快速爬取。

代码语言:javascript
复制
#使用Faker库随机生成虚假header
from faker import Faker
fake = Faker()
headers ={'User-Agent':fake.user_agent()}

留心

  • 写给之后的自己 文章是写完代码后,重新回顾的时候写的,回顾之后发现有很多需要优化的地方,比如异常处理部分经常考虑不周导致在爬取的时候异常中断,不得不重新排查错误。还有爬虫的断点续传的功能应该去了解学习下。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-06-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 咸鱼学Python 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 实战
  • 留心
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档