利用python的爬虫技术爬取百度贴吧的帖子

在爬取糗事百科的段子后,我又在知乎上找了一个爬取百度贴吧帖子的实例,为了巩固提高已掌握的爬虫知识,因而我打算本身也作一个。html

实现目标:1,爬取楼主所发的帖子python

              2,显示所爬去的楼层以及帖子题目正则表达式

              3,将爬取的内容写入到文件里,并实现动态显示爬取进度编程

实现工具:python的requests库和正则表达式以及bs4库app

首先咱们爬取的帖子网址为:https://tieba.baidu.com/p/3138733512?see_lz=1&pn=1,该网址是只看楼主的帖子的网址,所以该网站的源代码内容均为楼主所发贴的内容,爬取起来也比较方便。咱们发现须要爬取的帖子一共有5页,咱们能够经过for循环来进行对每一页信息的爬取。函数

接下来咱们来总体构建爬取的思路:工具

  1,爬取该网页的源代码post

  2,用正则表达式提取所需内容网站

  3,用正则匹配对所取内容进行精准修改以达到咱们想要的内容ui

  4,把内容写入到文件并显示写入进度

下面来介绍每一步的具体实现:

首先是获取源代码,这个已经比较简单了,大多数获取源代码的方式均可以用这段代码来实现:

def getHTMLText(url):
    try:
        user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
        headers = {'User-Agent': user_agent}
        r = requests.get(url,headers = headers)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        return r.text
    except:
        return ""

其中的user_agent配置能够在网页的源代码中找到,其目的是将爬虫进行假装成用户以此来获取更好的爬取体验

接下来咱们要经过正则表达式来获取咱们须要的“标题”,“帖子主要内容”以及“楼层”信息

经过分析源代码咱们发现“标题”在

<title>......</title>

中能够找到,“帖子主要内容”在

<div id="post_content_\d*" class="d_post_content j_d_post_content ">......</div>

中能够找到,“楼层”信息能够在

<span class="tail-info">......</span><span class="tail-info">

中找到。其中“.......”表示所要提取内容,咱们分别用两个函数来实现对此的提取

def printTitle(html):
    try:
        soup = BeautifulSoup(html, "html.parser")
        titleTag = soup.find_all('title')
        patten = re.compile(r'<title>(.*?)</title>', re.S)
        title = re.findall(patten, str(titleTag))
        return title
    except:
        return ""
def fillUnivlist(lis,li,html):
    try:
        patten = re.compile(r'<div id="post_content_\d*" class="d_post_content j_d_post_content ">(.*?)</div>', re.S)
        nbaInfo = re.findall(patten, str(html))
        pattenFloor = re.compile(r'<span class="tail-info">(\d*楼)</span><span class="tail-info">', re.S)
        floorText = re.findall(pattenFloor, str(html))
        number = len(nbaInfo)
        for i in range(number):
            Info = textTools.remove(nbaInfo[i])
            Info1 = textTools.remove(floorText[i])
            lis.append(Info1)
            li.append(Info)
    except:
        return ""

咱们对每一个方法都用try except 来保证其强健性。

可是咱们发现咱们对所提取的帖子内容有不少多余的成分:

<img class="BDE_Image" src="https://imgsa.baidu.com/forum/w%3D580/sign=cb6ab1f8708b4710ce2ffdc4f3ccc3b2/06381f30e924b899d8ca30e16c061d950b7bf671.jpg" pic_ext="jpeg"  pic_type="0" width="339" height="510"><br><br><br><br>50 惊喜新人王 <a href="http://jump2.bdimg.com/safecheck/index?url=x+Z5mMbGPAsY/M/Q/im9DR3tEqEFWbC4Yzg89xsWivS12AkS11WcjnMQsTddE2yXZInIi4k8KEu5449mWp1SxBADVCHPuUFSTGH+WZuV+ecUBG6CY6mAz/Zq1mzxbFxzAG+4Cm4FSU0="  class="ps_cb" target="_blank" onclick="$.stats.track(0, \'nlp_ps_word\',{obj_name:\'迈卡威\'});$.stats.track(\'Pb_content_wordner\',\'ps_callback_statics\')">迈卡威</a><br>上赛季数据<br>篮板 6.2  助攻 6.3  抢断 1.9 盖帽  0.6 失误 3.5 犯规  3  得分 16.7<br><br><br>       新赛季第50位,我给上赛季的新人王<a href="http://jump2.bdimg.com/safecheck/index?url=x+Z5mMbGPAsY/M/Q/im9DR3tEqEFWbC4Yzg89xsWivS12AkS11WcjnMQsTddE2yXZInIi4k8KEu5449mWp1SxBADVCHPuUFSTGH+WZuV+ecUBG6CY6mAz/Zq1mzxbFxzAG+4Cm4FSU0="  class="ps_cb" target="_blank" onclick="$.stats.track(0, \'nlp_ps_word\',{obj_name:\'迈卡威\'});$.stats.track(\'Pb_content_wordner\',\'ps_callback_statics\')">迈卡威</a>。 上赛季迈卡威在完全重建的<a href="http://jump2.bdimg.com/safecheck/index?url=x+Z5mMbGPAsY/M/Q/im9DR3tEqEFWbC4Yzg89xsWivTbCBRGuF91e6cwvXwi+nOsUCFQWyjKvntqT9uy6c+e1s3eo9XM+kBUaJGaqtq7WOznXcLnooXruQBvuApuBUlN"  class="ps_cb" target="_blank" onclick="$.stats.track(0, \'nlp_ps_word\',{obj_name:\'76人\'});$.stats.track(\'Pb_content_wordner\',\'ps_callback_statics\')">76人</a>中迅速掌握了球队,一开始就三双搞定了热火赢得了万千眼球。后来也屡屡有经验的表现,新秀赛季就拿过三双的球员很少,迈卡威如今能够说在76人站稳了脚跟。<br>       做为上赛季弱队的老大,<a href="http://jump2.bdimg.com/safecheck/index?url=x+Z5mMbGPAsY/M/Q/im9DR3tEqEFWbC4Yzg89xsWivS12AkS11WcjnMQsTddE2yXZInIi4k8KEu5449mWp1SxBADVCHPuUFSTGH+WZuV+ecUBG6CY6mAz/Zq1mzxbFxzAG+4Cm4FSU0="  class="ps_cb" target="_blank" onclick="$.stats.track(0, \'nlp_ps_word\',{obj_name:\'迈卡威\'});$.stats.track(\'Pb_content_wordner\',\'ps_callback_statics\')">迈卡威</a>刷出了不错的数据,但咱们静下心来看一看他,仍是发现他有不少问题。首先,投篮偏弱刚刚40%的命中率和惨淡的26%的三分命中率确定是不合格的!加之身体瘦弱,个字高大横移速度通常,防守端并无数据表现得这么好!做为控卫失误偏多,离巨星仍是有必定的差距,小子你是一飞冲天,仍是迅速陨落,就看你的努力了!<br>       说完缺点,来讲说优势,做为后卫篮板球很是突出,高大的身形能较好的影响对方的出手,也能发现己方的空位球员。突破虽然速度通常,但节奏感不错,大局观也在平均水准之上。提醒瘦而高大,不会投篮,突破节奏好,大局观不错!这在几年前说出来是谁?没错断腿前的<a href="http://jump2.bdimg.com/safecheck/index?url=x+Z5mMbGPAsY/M/Q/im9DR3tEqEFWbC4Yzg89xsWivT5ggWFC92MLwFHpDNBmn4rETPyFf5XUHwripOOA15C4U+GRIwDgEI46b99l0XyUM/jR49NyMTc/6qmUGNB+hoByExmB9N/65I="  class="ps_cb" target="_blank" onclick="$.stats.track(0, \'nlp_ps_word\',{obj_name:\'利文斯顿\'});$.stats.track(\'Pb_content_wordner\',\'ps_callback_statics\')">利文斯顿</a>! <br>       就球队地位而言,<a href="http://jump2.bdimg.com/safecheck/index?url=x+Z5mMbGPAsY/M/Q/im9DR3tEqEFWbC4Yzg89xsWivS12AkS11WcjnMQsTddE2yXZInIi4k8KEu5449mWp1SxBADVCHPuUFSTGH+WZuV+ecUBG6CY6mAz/Zq1mzxbFxzAG+4Cm4FSU0="  class="ps_cb" target="_blank" onclick="$.stats.track(0, \'nlp_ps_word\',{obj_name:\'迈卡威\'});$.stats.track(\'Pb_content_wordner\',\'ps_callback_statics\')">迈卡威</a>如今是绝对的老大,球你想怎么玩就怎么玩,数据你想怎么刷就怎么刷!去年的潜力新人<a href="http://jump2.bdimg.com/safecheck/index?url=x+Z5mMbGPAsY/M/Q/im9DR3tEqEFWbC4Yzg89xsWivTKm3O5uii9sKBrDcAE8/xDK4qTjgNeQuFPhkSMA4BCOOm/fZdF8lDP40ePTcjE3P+qplBjQfoaAchMZgfTf+uS"  class="ps_cb" target="_blank" onclick="$.stats.track(0, \'nlp_ps_word\',{obj_name:\'诺尔\'});$.stats.track(\'Pb_content_wordner\',\'ps_callback_statics\')">诺尔</a>是<a href="http://jump2.bdimg.com/safecheck/index?url=x+Z5mMbGPAsY/M/Q/im9DR3tEqEFWbC4Yzg89xsWivQdeSiO+EjvouPd1sAEaAOyK4qTjgNeQuFPhkSMA4BCOOm/fZdF8lDP40ePTcjE3P+qplBjQfoaAchMZgfTf+uS"  class="ps_cb" target="_blank" onclick="$.stats.track(0, \'nlp_ps_word\',{obj_name:\'蓝领\'});$.stats.track(\'Pb_content_wordner\',\'ps_callback_statics\')">蓝领</a>,其余人均可以清退,恩比德还受伤不能打,<a href="http://jump2.bdimg.com/safecheck/index?url=x+Z5mMbGPAsY/M/Q/im9DR3tEqEFWbC4Yzg89xsWivTbCBRGuF91e6cwvXwi+nOsUCFQWyjKvntqT9uy6c+e1s3eo9XM+kBUaJGaqtq7WOznXcLnooXruQBvuApuBUlN"  class="ps_cb" target="_blank" onclick="$.stats.track(0, \'nlp_ps_word\',{obj_name:\'76人\'});$.stats.track(\'Pb_content_wordner\',\'ps_callback_statics\')">76人</a>队的战绩怎么样,就看你了!可是等到诺尔成熟(假如不是水货),恩比德伤愈(他技术上不可能水,只是看伤病了)你就有一队很好的内线组合了!你能把他们带成什么成绩,这时候就是考验你迈卡威除了刷数据还有什么能力的时候了。'

这段提取的信息里有着大量多余的信息,所以须要咱们进行细分,基本思路为将多余的信息用正则匹配出来,而后利用正则的替换方法把这些多余的内容替换为空格或者换行

在这里,咱们来构建一个处理信息的类

class Tools:
    removeImg = re.compile('<img.*?>')
    removBr = re.compile('<br>')
    removeHef = re.compile('<a href.*?>')
    removeA = re.compile('</a>')
    removeClass = re.compile('<a class.*?>|<aclass.*?>')
    removeNull = re.compile(' ')


    def remove(self,te):
        te = re.sub(self.removeImg,'',te)
        te = re. sub(self.removBr,'\n',te)
        te = re.sub(self.removeHef,'',te)
        te = re.sub(self.removeA,'',te)
        te = re.sub(self.removeClass,'',te)
        te = re.sub(self.removeNull, '', te)
        return  te

将刚才乱码的信息通过这个类的处理后,咱们能够获得下列信息:

50惊喜新人王迈卡威
上赛季数据
篮板6.2助攻6.3抢断1.9盖帽0.6失误3.5犯规3得分16.7


新赛季第50位,我给上赛季的新人王迈卡威。上赛季迈卡威在完全重建的76人中迅速掌握了球队,一开始就三双搞定了热火赢得了万千眼球。后来也屡屡有经验的表现,新秀赛季就拿过三双的球员很少,迈卡威如今能够说在76人站稳了脚跟。
做为上赛季弱队的老大,迈卡威刷出了不错的数据,但咱们静下心来看一看他,仍是发现他有不少问题。首先,投篮偏弱刚刚40%的命中率和惨淡的26%的三分命中率确定是不合格的!加之身体瘦弱,个字高大横移速度通常,防守端并无数据表现得这么好!做为控卫失误偏多,离巨星仍是有必定的差距,小子你是一飞冲天,仍是迅速陨落,就看你的努力了!
说完缺点,来讲说优势,做为后卫篮板球很是突出,高大的身形能较好的影响对方的出手,也能发现己方的空位球员。突破虽然速度通常,但节奏感不错,大局观也在平均水准之上。提醒瘦而高大,不会投篮,突破节奏好,大局观不错!这在几年前说出来是谁?没错断腿前的利文斯顿!
就球队地位而言,迈卡威如今是绝对的老大,球你想怎么玩就怎么玩,数据你想怎么刷就怎么刷!去年的潜力新人诺尔是蓝领,其余人均可以清退,恩比德还受伤不能打,76人队的战绩怎么样,就看你了!可是等到诺尔成熟(假如不是水货),恩比德伤愈(他技术上不可能水,只是看伤病了)你就有一队很好的内线组合了!你能把他们带成什么成绩,这时候就是考验你迈卡威除了刷数据还有什么能力的时候了。

这样的表达效果就可让我清晰看到提取到的信息,因此这个类是成功的。接下来咱们只须要将提取的信息输出就行。

咱们先写一个写入标题信息和主体内容的方法,由于标题只在第一个网页上因此能够单独写一个方法

def writeText(titleText,fpath):
    try:
        with open(fpath, 'a', encoding='utf-8') as f:
            f.write(str(titleText) + '\n')
            f.write('\n')
            f.close()
    except:
        return ""
def writeUnivlist(lis,li,fpath,num):
    with open(fpath, 'a', encoding='utf-8') as f:
        for i in range(num):
            f.write(str(lis[i])+'\n')
            f.write('*'*50 + '\n')
            f.write(str(li[i]) + '\n')
            f.write('*' * 50 + '\n')
        f.close()

 接下来咱们只须要写一个执行的主函数便可,咱们定义一下所要写入文件的路径,而后先写入文件的标题

    count = 0
    url = 'https://tieba.baidu.com/p/3138733512?see_lz=1&pn=1'
    output_file = 'D:/StockInfo.txt'
    html = getHTMLText(url)
    titleText = printTitle(html)
    writeText(titleText, output_file)

接下来利用for循环来实现对每一个网页的信息的输入,并打印写入文件的进度

    for i in range(5):
        i = i + 1
        lis = []
        li = []
        url = 'https://tieba.baidu.com/p/3138733512?see_lz=1&pn=' + str(i)
        html = getHTMLText(url)
        fillUnivlist(lis, li, html)
        writeUnivlist(lis, li, output_file, len(lis))
        count = count + 1
        print("\r当前进度: {:.2f}%".format(count * 100 / 5), end="")

以上就是爬取百度贴吧的帖子的因此内容,最后我认为若是咱们将这些函数方法封装成一个类,效果会更好。

如下是所有代码

import  requests
from bs4 import BeautifulSoup
import re


class Tools:
    removeImg = re.compile('<img.*?>')
    removBr = re.compile('<br>')
    removeHef = re.compile('<a href.*?>')
    removeA = re.compile('</a>')
    removeClass = re.compile('<a class.*?>|<aclass.*?>')
    removeNull = re.compile(' ')


    def remove(self,te):
        te = re.sub(self.removeImg,'',te)
        te = re. sub(self.removBr,'\n',te)
        te = re.sub(self.removeHef,'',te)
        te = re.sub(self.removeA,'',te)
        te = re.sub(self.removeClass,'',te)
        te = re.sub(self.removeNull, '', te)
        return  te

textTools = Tools()

def getHTMLText(url):
    try:
        user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
        headers = {'User-Agent': user_agent}
        r = requests.get(url,headers = headers)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        return r.text
    except:
        return ""

def printTitle(html):
    try:
        soup = BeautifulSoup(html, "html.parser")
        titleTag = soup.find_all('title')
        patten = re.compile(r'<title>(.*?)</title>', re.S)
        title = re.findall(patten, str(titleTag))
        return title
    except:
        return ""

def fillUnivlist(lis,li,html):
    try:
        patten = re.compile(r'<div id="post_content_\d*" class="d_post_content j_d_post_content ">(.*?)</div>', re.S)
        nbaInfo = re.findall(patten, str(html))
        pattenFloor = re.compile(r'<span class="tail-info">(\d*楼)</span><span class="tail-info">', re.S)
        floorText = re.findall(pattenFloor, str(html))
        number = len(nbaInfo)
        for i in range(number):
            Info = textTools.remove(nbaInfo[i])
            Info1 = textTools.remove(floorText[i])
            lis.append(Info1)
            li.append(Info)
    except:
        return ""

def writeText(titleText,fpath):
    try:
        with open(fpath, 'a', encoding='utf-8') as f:
            f.write(str(titleText) + '\n')
            f.write('\n')
            f.close()
    except:
        return ""

def writeUnivlist(lis,li,fpath,num):
    with open(fpath, 'a', encoding='utf-8') as f:
        for i in range(num):
            f.write(str(lis[i])+'\n')
            f.write('*'*50 + '\n')
            f.write(str(li[i]) + '\n')
            f.write('*' * 50 + '\n')
        f.close()

def main():
    count = 0
    url = 'https://tieba.baidu.com/p/3138733512?see_lz=1&pn=1'
    output_file = 'D:/StockInfo.txt'
    html = getHTMLText(url)
    titleText = printTitle(html)
    writeText(titleText, output_file)
    for i in range(5):
        i = i + 1
        lis = []
        li = []
        url = 'https://tieba.baidu.com/p/3138733512?see_lz=1&pn=' + str(i)
        html = getHTMLText(url)
        fillUnivlist(lis, li, html)
        writeUnivlist(lis, li, output_file, len(lis))
        count = count + 1
        print("\r当前进度: {:.2f}%".format(count * 100 / 5), end="")

main()

这个还有不少完善的地方,但愿你们多多指教

                                                  -------来自一个热爱自学编程的小白

相关文章
相关标签/搜索