【爬虫实战一】之糗事百科热门段子采集

糗事百科段子采集的实例已经有很多前辈写过了,但年代久远,普遍基于python2.7,并且没有用到BeautifulSoup,而是自己写正则表达式进行匹配,因此,每次网站改版后,代码重构的工作量比较大。
本着造福群众(找项目练手)的原则,笔者写了一个基于python3、requests库和BeautifulSoup库的糗事百科段子采集爬虫。

1.先导入所需模块,再创建一个QSBK的类

import requests
from bs4 import BeautifulSoup


class QSBK(object):
    def __init__(self):
        # 页码
        self.page_num = 1
        # 存储采集到的段子
        self.stories = {}

2.审查采集页面,确定采集策略

糗事百科热门段子任意一个页面的url是

https://www.qiushibaike.com/8hr/page/2/?s=4993718

?后面的内容先忽略,分析后,很明显2代表第二页,以此类推,可以找出url的规律。本实例使用requests库进行Http解析,不够需要注意一点,糗事百科会对use_agent为机器的访问者自动拦截,因此采集前需设置一下header中的use_agent。

    # 获取糗事百科hot页面
    def get_page(self):
        # 初始化url
        url = 'https://www.qiushibaike.com/8hr/page/' + str(self.page_num)
        # 设置请求头,绕开网站的user_agent筛选
        user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
        headers = {'use_agent': user_agent}
        # Get页面
        res = requests.get(url, headers=headers)
        # 设置页面编码
        res.encoding = 'utf-8'
        # 返回Beautiful Soup对象
        return BeautifulSoup(res.text, 'html.parser')

观察发现,糗事百科段子分为两类:纯文字段子和图片+文字段子。采集图片并不复杂(python的urlretrieve)可以解决这个问题,但是在console展现图片则很是麻烦。因此,本项目只采集纯文字段子。
BeautifulSoup强大易用的tag解析是本项目的发动机。在用Chrome的审查元素功能查看网页结构后,便能释放bs的强大力量。

    # 获取整个页面不带图片的段子
    @staticmethod
    def get_page_stories(bs_obj):
        # 用于保存每个页面段子的数据结构
        page_stories = []
        # 利用Beautiful Soup采集页面段子
        items = bs_obj.find('div', {'id': 'content-left'}). \
            findAll('div', {'class': 'article block untagged mb15'})
        for item in items:
            # 剔除带图片的段子
            if not item.find('div', {'class': 'thumb'}):
                # author、content、vote_num、stats_num、god_cmt分别代表段子作者、段子正文、觉得段子好笑的人数、段子评论数、神评论
                author = item.find('div', {'class': 'author clearfix'}).select('h2')[0].text
                content = item.find('a', {'class': 'contentHerf'}). \
                    find('div', {'class': 'content'}).text
                vote_num = item.find('div', {'class': 'stats'}). \
                    find('span', {'class': 'stats-vote'}).find('i').text
                stats_num = item.find('div', {'class': 'stats'}). \
                    find('span', {'class': 'stats-comments'}).find('i').text
                # igc = indexGodCmt
                igc = item.find('a', {'class': 'indexGodCmt'})
                if igc:
                    god_cmt = {'name': igc.find('div', {'class': 'cmtMain'}).find('span', {'class': 'cmt-name'}).text,
                               'cmt': igc.find('div', {'class': 'cmtMain'}).find('div', {'class': 'main-text'}).contents[0]}
                else:
                    god_cmt = None
            else:
                continue
            # 格式化段子
            if god_cmt:
                story = '糗友“%s”:\n%s\n%s人觉得好笑|评论数:%s\n“神评论”\n%s:%s' % \
                        (author.strip(), content.strip(), vote_num, stats_num,
                         god_cmt['name'].strip(), god_cmt['cmt'].strip())
            else:
                story = '糗友“%s”:\n%s\n%s人觉得好笑|评论数:%s' % \
                        (author.strip(), content.strip(), vote_num, stats_num)
            # 将段子保存在page_stories中
            page_stories.append(story)
        # 返回page_stories
        return page_stories

代码有点眼花缭乱,这应该是网页各式各样的标签的功劳。

3.储存段子、加载页面、展示结果

    # 储存采集到的页面段子
    def store_stories(self, page_stories):
        self.stories[self.page_num] = page_stories

    # 如果保存在stories中的段子页面少于2,则加载下一个页面的段子
    def load_page(self):
        if len(self.stories) < 2:
            page_stories = QSBK.get_page_stories(self.get_page())
            self.store_stories(page_stories)
            self.page_num += 1

    # 按一次回车,展示一个采集到的段子
    def display(self):
        active = True
        while active:
            self.load_page()
            page_stories = self.stories.pop(self.page_num - 1)

            for story in page_stories:
                if input('按回车键显示一个段子(输入q退出):').lower() == 'q':
                    active = False
                    break
                print(story)

4.效果演示

joke = QSBK()
joke.display()

这里写图片描述

最后非常感谢静觅博主(http://cuiqingcai.com/)的教程给予的帮助,本文有许多部分参考了其博文中的设计思路和方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值