使用Python爬取糗百段子

最近在自学python爬虫,写了一个小demo,前来现学现卖大笑大笑大笑

感谢大神的博客!让我受益匪浅。python爬虫系列教程

开始之前啰嗦一句:不要因为我们的学习行为,影响到人家网站的正常运营

好了,开整!

首先博主用的是python3.6版本,据说python3的用户很少,我这也算个非主流了。。。

查看python版本,使用命令行直接敲入“python”命令即可

首先,来一小段代码开开胃:

import requests


class py:
    def get_html(self, url):
        html = requests.get(url)
        print(html.text)

qiubai = py()
qiubai.get_html('http://www.qiushibaike.com/')

这里是使用了python的requests库进行http的get请求,requests库可以在命令行使用“pip install requests”安装。运行上述代码,会在控制台输出糗百首页的html源码,也是我们接下来工作的主要对象。


在google浏览器上按下F12可以调用开发者工具,看到网页的源码,而我们所关注的信息是在id为“content-left”的<div>标签下,每一个class为“article block untagged mb15”的<div>标签都是一个段子的信息,包括作者,内容,图片,好笑数,评论数,点赞数,点踩数等等。而class为“pagination”的<ul>标签则包含了页面跳转的链接。

我们的解析信息工作,从一个正则表达式开始(糗百会不定期改版,这条正则到时候可能就不好使了,小伙伴需要发挥自己的聪明才智了哦):

            html = request.get(next_url, 3)
            pattern = re.compile('<div class="author clearfix">.*?href.*?<img src.*?title=.*?<h2>(.*?)</h2>.*?'
                                 '<div class="content">.*?<span>(.*?)</span>.*?</div>.*?</a>(.*?)<div class="stats">'
                                 '.*?class="stats-vote"><i class="number">(.*?)</i>.*?<i class="number">(.*?)</i>.*?'
                                 'hidden">(.*?)</span>.*?hidden">-(.*?)</span>', re.S)
            # item[0] 用户昵称
            # item[1] 发布内容
            # item[2] 如果有内容,则为图片相关;否则是连续的\n符
            # item[3] 好笑
            # item[4] 评论数
            # item[5] 赞
            # item[6] 踩
            items = re.findall(pattern, html.text)
            # 匹配所有的<br/>字符
            replaceBR = re.compile(r'<br/>')
            # 匹配所有的\n串
            replaceN = re.compile(r'(\n)+')
            for item in items:
                # 将item[2]中的连续的\n字符串替换成一个None字符
                img = re.sub(replaceN, 'None', item[2])
                if img == 'None':
                    print(item[0])
                    # 将item[1]中的所有的<br/>字符替换成换行符
                    print(re.sub(replaceBR, '\n', str(item[1])))
                    print(u'好笑:', item[3], u' 评论:', item[4], u' 赞:', item[5], u'踩:', item[6])

所以匹配到的字符都会加入到一个我们定义的名为items的数组中,这个数组的长度最小为0(没有匹配),数组的每个元素又是一个长度为7的数组(因为我们在正则表达式中共有7个"(.*?)")。

乍一看这个正则表达式,有的人可能会有点懵逼,我们只看它的一小部分,“窥一斑而知全豹”,听贫道慢慢道来。


每个段子包含的第一部分内容,就是作者的一些个人信息,<img>标签的链接是作者头像,<h2>标签中的内容是作者的昵称,再往下的<div>标签显示了作者的性别和年龄。我们的正则表达式匹配的就是以“author clearfix">”开头的,后续任意字符(也就是“.*?”,匹配任意长度任意字符),然后匹配“href”字符等等,以此类推,直到“<h2>(.*?)</h2>”这里我们注意一下,在上图中我们可以看到,它匹配的是“<h2>Boltzmann</h2>”这段,“(.*?)”匹配的也就是用户的昵称。

正则表达式是个好东西,不过博主是不怎么懂的,想学习的小伙伴可以自行查找资料,学有所成了记得来教教博主啊!感激不尽!

通过上述的代码我们可以获取当前页的所有段子,但是既然说是爬虫,我们的小虫子得主动出击啊,爬取一页之后应该去下一个页面继续工作。当然不是所有的网站都有类似“下一页”、“更多”这样的按钮的,那样的网站如何爬取遇到再说;幸运的是,糗百有啊,那我们还等什么,整!

上文说过,页面跳转的链接都在class为"pagination"的<ul>标签中,每个<li>标签都是一个地址链接,我们需要做的工作就是:

1. 找到这个<ul>标签

2. 找到<ul>标签下所有的<li>标签

3. 从<li>标签中找到下一个页面的地址链接

这里给大家介绍一个简单粗暴的python库,叫 BeautifulSoup,使用这个库推荐安装lxml,安装命令当然是“pip install lxml”。

上代码:

# 获取class为pagination的ul标签,获取其中的页面跳转相关内容
            pagination = BeautifulSoup(html.text, 'lxml').find('ul', class_='pagination')
            #  获取pagination中所有的li标签,大多数最后一个标签都包含下一个页面的地址
            li = BeautifulSoup(str(pagination), 'lxml').find_all('li')
            next_pattern = re.compile('<a href="(.*?)" rel', re.S)
            # 检测最后一个li标签是否含有地址信息
            next = re.findall(next_pattern, str(li[-1]))
            # print(li)
            # 当下个页面链接不为空时,检测数据库中是否已经存在连接
            if next:
                print('the next page is:', next[-1])
                # 如果地址在库中存在,终止操作,否则拼接好url,继续执行后续操作
                if url_queue.find_by_id(next[-1]):
                    break;
                # 地址信息入库
                info = {
                    '_id': next[-1],
                    'timestamp': datetime.now()
                }
                url_queue.push(info)
                next_url = base_url + next[-1]

            # 当下个页面链接为空时,退出循环
            else:
                print(r'I don\'t konw where to go : ', next)
                break
细心的小伙伴发现了这里使用了数 据 库的操作,我这里用的是简单的插入和查询操作判断地址是否爬取过,逻辑处理得也很是草率,希望小伙伴们在自己使用的过程中加以改良,奉上mongodb操作的代码:

from pymongo import MongoClient, errors


class MongoQueue():

    # 初始化mongodb连接
    def __init__(self, db, collection, timeout=300):
        self.client = MongoClient()
        self.Client = self.client[db]
        self.db = self.Client[collection]
        self.timeout = timeout

    # 将数据插入数据库
    def push(self, info):
        try:
            self.db.insert(info)
            print('插入成功')
        except errors.DuplicateKeyError as e:
            print('插入失败')
            print(e)
            pass

    # 根据id查找数据库中的记录
    def find_by_id(self, id):
        recode = self.db.find_one(
            {
                '_id': id
            }
        )
        return recode

    def clear(self):
        self.db.drop()

代码已上传csdn资源,大家可以免费下载,点击打开链接 欢迎大家拍砖~~~

最后再叮嘱一句:不要影响到人家网站的正常运营!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值