写出你的第一个小爬虫

在上一篇文章中对Python有了一定的基础学习后,我们现在要开始对网页进行爬取啦。

这次我们要爬取的网站是中国移动集团的运维案例文章和评论内容。这篇文章中将会涉及到GET请求和POST请求,以及BeautifulSoup的使用。

扩展模块的安装

要让python可以对网页发起请求,那就需要用到requests之类的包。我们可以用命令行来下载安装,打开cmd,直接输入命令就会自动下载安装,非常的方便。

pip install requests

既然用到了pip,那就顺便解释一下这个东东。

pip 是 Python 著名的包管理工具,在 Python 开发中必不可少。一般来说当你安装完python后,pip也会自动安装完毕,可以直接享用,十分鲜美。

附上一些常用的pip命令

# 查看pip信息
pip –version

#升级pip
pip install -U pip

# 查看已经安装的包
pip list

# 安装包
Pip install PackageName

# 卸载已经安装好的包
Pip uninstall PackageName

以上这四个命令非常的实用,我在做这个爬虫期间有多次使用到。

在安装完requests包后,还需要再安装一个神器BeautifulSoup,配合lxml库,这是最近非常流行的两个库,这个是用来解析网页的,并提供定位内容的便捷接口,API非常人性化,支持CSS选择器、Python标准库中的HTML解析器,也支持 lxml 的 XML解析器

语法使用类似于XPath。通过官方的文档的阅读,很容易上手。

安装方式:

  • BeautifulSoup的安装
pip install beautifulsoup4
  • lxml的安装
pip install lxml

不报错即为安装成功

BeautifulSoup官方文档传送门

安装完上面三个包后,就开始制作我们的第一个小爬虫吧

我们先来分析一下我们这次要爬取数据的网站数据。可以使用chrome浏览器自带的工具来抓包,按F12,选择Network,就可以看到所有的请求内容了。当然也可以用Fiddler这个优秀的工具来抓包,还能对请求进行截获并修改参数,大家有时间的话可以去玩一玩。这儿因为方便,我就采用了chrome浏览器自带的来进行分析了。

根据这个请求,我们能看出这个是一个GET请求。我们将headers里的内容绑定到类的属性里,接着绑定一个请求的地址。

import requests  #导入requests 模块
from bs4 import BeautifulSoup  #导入BeautifulSoup 模块

# 爬取文章案例编号和当前周期有效阅读数
class BeautifulGetCaseSN():
    def __init__(self):  #类的初始化操作
        #头部信息
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0',
            'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
            'Accept-Language':'zh-CN,zh;q=0.8',
            'Connection':'keep-alive',
            'Cookie':'JSESSIONID=48A82C60BE65ED14C5978297C03AF776; PHPSESSID=ST-10-QybrBt31XVfPBqKAT2jr'
        }  
        #要访问的网页地址
        self.web_url = 'http://net.chinamobile.com/cmccnkms-case/web/casesPortal/getCaseInfor.action?caseId=75058'  

接下来我们再来分析一下要爬取的内容,下图中的三个框是我们要爬取的目标内容,分别是标题,当前周期有效阅读数,案例编号。

分别右击审查元素,分析一下HTML的结构,以方便用BeautifulSoup来解析。

看了一遍这个网页的HTML,发现写这个网站的人真的是随意发挥,哈哈哈,都是直接用标签对的,标签class属性或者id属性几乎都没有,还好我们现在有了神器Beautifulsoup再手,根本不用愁无从下手这种的事儿。

通过分析,我们发现标题和当前有效周期的父级标签都是

,而且我搜索了下,发现width=“78%”属性只有这两个标签有。那么好办了,利用Beautifulsoup能对CSS属性解析的特性,我们就从这个属性下手。接着通过对案例编号的分析,我们发现这个

标签有一个class属性,那就根据这个属性进行获取。

def get_data(self):
    print('开始文章基础信息GET请求')
    r = requests.get(self.web_url, headers=self.headers)
    all_soup = BeautifulSoup(r.text, 'lxml')

    caseSn = all_soup.find_all('td','txleft') #案例编号抓取
    print(caseSn[2].text)

    all_a = all_soup.find_all('td',width='78%')
    title = all_a[0].find('h4').text #标题抓取
    print(title)

    read_num = all_a[1].find_all('span')
    print(read_num[3].text) #有效阅读数抓取

解释一下这段代码:

r = requests.get(self.web_url, headers=self.headers)
all_soup = BeautifulSoup(r.text, 'lxml')

对网站进行GET请求,GET请求需要的参数有请求地址和头部信息,然后将获取的文本放入BeautifulSoup进行解析。这儿顺带说一句,python语言真的是人生苦短啊,请求网址,解析网页2句话就能完成,简洁的不得了,当然这个BeautifulSoup我为了逻辑清楚分开写了,不然也是能用一句代码来完成的。

caseSn = all_soup.find_all('td','txleft') #案例编号抓取
print(caseSn[2].text)

解析获取所有class类名为txleft的td标签,然后发现我们需要的案例编号是在第三个tag中,获取这个tag的文本内容。

all_a = all_soup.find_all('td',width='78%')
title = all_a[0].find('h4').text #标题抓取
print(title)

read_num = all_a[1].find_all('span')
print(read_num[3].text) #有效阅读数抓取

通过打断点的方式,我们可以看到解析获取所有宽度属性为78%的td标签,一共有2个tag集,再在第1个标签集中解析获取为h4的标签,这个全文只存在唯一的一个,所以就获取到了我们所需要的文章标题。有效阅读数获取同理,在第2个标签集继续中解析获取叫span的标签,有效阅读数的内容藏在第四个span标签中。

关于BeautifulSoup的find_all()find()的官方使用说明:

find_all(name, attrs, recursive, text, **kwargs)
find_all()方法搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件.

find( name , attrs , recursive , text , **kwargs )
find_all() 方法将返回文档中符合条件的所有tag,尽管有时候我们只想得到一个结果.比如文档中只有一个

标签,那么使用 find_all() 方法来查找标签就不太合适, 使用 find_all 方法并设置 limit=1 参数不如直接使用 find() 方法.

现在让我们来实例化一个爬虫,满怀憧憬的按下F5,让他跑起来。

getCaseSN = BeautifulGetCaseSN()  #创建类的实例,根据caseId爬取文章基础信息
getCaseSN.get_data()
print('爬取具体信息over')

在调试控制台里查看结果。
哇!爬取数据成功!第一个小爬虫诞生了。

然鹅!现在还不能开始庆祝,毕竟任务才进行到一半。接下来,我们根据需求,还需要爬取文章的评论者的名字做爬取统计。继续对网页进行分析。

需要对上图中的评论者姓名进行爬取,而且还需要做到翻页。

通过对请求的分析,发现这个评论块是个独立的请求,然后加入到文章页面的标签块中。点进去发现这是个POST请求,带有Form数据。通过对数据分析,发现有3个元素,第一个是评论的排序方式,我们不用动他,第二个是页码,就是翻页的关键参数,第三个是文章的Id。

开始构建POST请求

# 爬取具体信息
class BeautifulGetData():
    def __init__(self):  #类的初始化操作
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0',
            'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
            'Accept-Language':'zh-CN,zh;q=0.8',
            'Connection':'keep-alive',
            'Cookie':'JSESSIONID=48A82C60BE65ED14C5978297C03AF776; PHPSESSID=ST-10-QybrBt31XVfPBqKAT2jr''
        }
        #要访问的网页地址
        self.web_url = 'http://net.chinamobile.com/cmccnkms-case/web/casesPortal/loadComments.action'  

    def get_data(self):
        print('开始文章评论内容POST请求')
        print('具体评论获取n')
        for x in range(1,10):
            #post请求的数据
            web_data = {
                'sort':'desc',
                'pageNum':x,
                'caseId':75058
            }
            r = requests.post(self.web_url,data=web_data, headers=self.headers)

这里增加一个for循环就是为了模拟请求的页码,根据pageNum的不同,对该网址进行多次请求获取不同页面信息。

通过分析评论页的HTML数据,我发现每个评论都用

包含,于是我们可以用find_all来获取全部的这个class,因为每页都有五个评论,所以可以用for循环来进行分析并输出。
下面是完整的请求代码

def get_data(self):
        print('开始文章评论内容POST请求')
        print('具体评论获取n')
        get_name = []
        get_next_name = []
        for x in range(1,10):
            web_data = {
                'sort':'desc',
                'pageNum':x,
                'caseId':75058
            }
            r = requests.post(self.web_url,data=web_data, headers=self.headers)
            all_a = BeautifulSoup(r.text, 'lxml').find_all('div','month')
            print('第',x,'页')            
            
            #将上页获取的评论记录并清空当前页
            get_name = get_next_name
            get_next_name = []

            for a in enumerate(all_a):                 
                str_name = a[1].text.split(':') #对获取的文本内容做切割
                get_next_name.append(str_name[0]) #将名字加入到当前获取记录中
            
            if get_name == get_next_name:
                print('完成')
                break
            else:
                for a in get_next_name:
                    print(a)

这里说一下我定义的两个list:get_nameget_next_name。之所以定义这两个是因为每篇文章的评论数量我是不知道的,所以我不能直接控制需要爬取的页数,只能尽可能大的写一个数。但是当页数小于我设定的页码值后会发生如下的数据重复显示事件。

于是我加入了这两个参数,来存放前一页的获取的数据,如果单页获取的数据与前一页获取的数据相同,那说明就是到了评论的最后一页,直接跳出循环,结束该篇文章的评论爬取。

好了,把这两个类实例化一下,然后开始run起来吧。

getCaseSN = BeautifulGetCaseSN()  #创建类的实例,根据caseId爬取文章基础信息
getData = BeautifulGetData()  #创建类的实例,根据caseId爬取文章评论信息
getCaseSN.get_data()
getData.get_data()

成功获取到了我希望得到的目标数据,完美!

后记

但是,只对一篇固定文章的爬取,远远不是我的最终目的,我的目的是,导入一份需要爬取的表格,然后进行自动的爬取,并将获取的数据输出并保存下来。在下一篇文章中,我就来讲一讲,Excel文件的导入读取与文件的导出保存。

推荐阅读更多精彩内容

  • Power BI 增量刷新
    1. 从数据库行数合适的table做测试 (一开始找了8千万行的数据,但是导入太慢了,1个小时都没导完,就换了了1...
    PowerBiER阅读 252评论 0赞 3
  • 学习Python 爬虫没思路?你可以看看这篇文章
    可以说爬虫是学习 Python 的入门必修课。当能独立写出第一个完整的爬虫的时候,我们已经迈出了一大步。因为在这过...
    黑羽_692867294阅读 255评论 0赞 6
  • python爬虫福利:带你爬取妹子图上的美女图片,学习改变生活
    学习python爬虫,总得实战演练一下才能真正有所收获。今天我们就来用python爬虫爬取妹子图,哇~全是美女哦!...
    python知道阅读 555评论 2赞 6
  • Python爬虫新手入门教学(十):爬取彼岸4K超清壁纸
    前言 本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理。 Pyt...
    松鼠爱吃饼干阅读 90评论 0赞 2
  • Python批量爬取代理ip,并自动插入到Excel表格!
    思路: 以“http://www.66ip.cn/”网址为例,使用requests访问,通过xpath解析相关标签...
    爱是一道光_e5f7阅读 501评论 0赞 10
评论6
赞60
60赞61赞
1赞赏
下载App

{"dataManager":"[]","props":{"isServer":true,"initialState":{"global":{"done":false,"artFromType":null,"fontType":"black","modal":{"ContributeModal":false,"RewardListModal":false,"PayModal":false,"CollectionModal":false,"LikeListModal":false,"ReportModal":false,"QRCodeShareModal":false,"BookCatalogModal":false,"RewardModal":false},"ua":{"value":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36","isIE11":false,"earlyIE":null,"chrome":"58.0","firefox":null,"safari":null,"isMac":false},"$diamondRate":{"displayable":false,"rate":0},"readMode":"day","locale":"zh-CN","seoList":[{"comments_count":0,"public_abbr":"1. 从数据库行数合适的table做测试 (一开始找了8千万行的数据,但是导入太慢了,1个小时都没导完,就换了了1...","share_image_url":"https://upload-images.jianshu.io/upload_images/17739247-606bef2b4608043c.png","slug":"de296178655c","user":{"id":17739247,"nickname":"PowerBiER","slug":"fb85a317263f","avatar":"https://upload.jianshu.io/users/upload_avatars/17739247/9c0e39d3-4589-4031-b1f4-1520edea8436"},"likes_count":3,"title":"Power BI 增量刷新","id":83224916,"views_count":252},{"comments_count":0,"public_abbr":"可以说爬虫是学习 Python 的入门必修课。当能独立写出第一个完整的爬虫的时候,我们已经迈出了一大步。因为在这过...","share_image_url":"https://upload-images.jianshu.io/upload_images/24716216-f627dd4f37f48529.png","slug":"b1f1cdb139fe","user":{"id":24716216,"nickname":"黑羽_692867294","slug":"270aaf625f00","avatar":"https://upload.jianshu.io/users/upload_avatars/24716216/98bdc1da-d43f-4f53-b827-8763837f3877.jpg"},"likes_count":6,"title":"学习Python 爬虫没思路?你可以看看这篇文章","id":81059415,"views_count":255},{"comments_count":2,"public_abbr":"学习python爬虫,总得实战演练一下才能真正有所收获。今天我们就来用python爬虫爬取妹子图,哇~全是美女哦!...","share_image_url":"https://upload-images.jianshu.io/upload_images/25361073-913e87293a29449e.png","slug":"cf71b9b49b49","user":{"id":25361073,"nickname":"python知道","slug":"e0518e327121","avatar":"https://upload.jianshu.io/users/upload_avatars/25361073/7fde370e-7534-44b1-8981-45ee4530f34f.png"},"likes_count":6,"title":"python爬虫福利:带你爬取妹子图上的美女图片,学习改变生活","id":82805758,"views_count":555},{"comments_count":0,"public_abbr":"前言 本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理。 Pyt...","share_image_url":"https://upload-images.jianshu.io/upload_images/24396660-8bfef62a4a376e56.image","slug":"5f02acfbd5e3","user":{"id":24396660,"nickname":"松鼠爱吃饼干","slug":"0dcc8b077292","avatar":"https://upload.jianshu.io/users/upload_avatars/24396660/343f1f0e-254a-4bdc-8dbf-ac04193967e0.jpg"},"likes_count":2,"title":"Python爬虫新手入门教学(十):爬取彼岸4K超清壁纸","id":83244504,"views_count":90},{"comments_count":0,"public_abbr":"思路: 以“http://www.66ip.cn/”网址为例,使用requests访问,通过xpath解析相关标签...","share_image_url":"https://upload-images.jianshu.io/upload_images/24596166-e7a74b6176b089fe","slug":"5713105d84f7","user":{"id":24596166,"nickname":"爱是一道光_e5f7","slug":"7e41657d7c21","avatar":"https://upload.jianshu.io/users/upload_avatars/24596166/dc6d513e-c787-446a-9fad-7ebd19480c79"},"likes_count":10,"title":"Python批量爬取代理ip,并自动插入到Excel表格!","id":79259334,"views_count":501}]},"note":{"data":{"is_author":false,"last_updated_at":1539252382,"public_title":"手把手系列:用Python3+PyQt5做一个有界面的小爬虫(二)","purchased":false,"liked_note":false,"comments_count":6,"free_content":"u003chru003enu003ch3u003e写出你的第一个小爬虫u003c/h3u003enu003cpu003e在上一篇文章中对Python有了一定的基础学习后,我们现在要开始对网页进行爬取啦。u003c/pu003enu003cpu003e这次我们要爬取的网站是中国移动集团的运维案例文章和评论内容。这篇文章中将会涉及到GET请求和POST请求,以及BeautifulSoup的使用。u003c/pu003enu003ch5u003e扩展模块的安装u003c/h5u003enu003cpu003e要让python可以对网页发起请求,那就需要用到requests之类的包。我们可以用命令行来下载安装,打开cmd,直接输入命令就会自动下载安装,非常的方便。u003c/pu003enu003cpreu003eu003ccodeu003epip install requestsnu003c/codeu003eu003c/preu003enu003cpu003e既然用到了pip,那就顺便解释一下这个东东。u003c/pu003enu003cpu003epip 是 Python 著名的包管理工具,在 Python 开发中必不可少。一般来说当你安装完python后,pip也会自动安装完毕,可以直接享用,十分鲜美。u003c/pu003enu003cpu003eu003cstrongu003e附上一些常用的pip命令u003c/strongu003eu003c/pu003enu003cpreu003eu003ccodeu003e# 查看pip信息npip –versionnn#升级pipnpip install -U pipnn# 查看已经安装的包npip listnn# 安装包nPip install PackageNamenn# 卸载已经安装好的包nPip uninstall PackageNamenu003c/codeu003eu003c/preu003enu003cpu003e以上这四个命令非常的实用,我在做这个爬虫期间有多次使用到。u003c/pu003enu003cpu003e在安装完requests包后,还需要再安装一个神器BeautifulSoup,配合lxml库,这是最近非常流行的两个库,这个是用来解析网页的,并提供定位内容的便捷接口,API非常人性化,支持CSS选择器、Python标准库中的HTML解析器,也支持 lxml 的 XML解析器u003c/pu003enu003cpu003e语法使用类似于XPath。通过官方的文档的阅读,很容易上手。u003c/pu003enu003cpu003eu003cstrongu003e安装方式:u003c/strongu003eu003c/pu003enu003culu003enu003cliu003eBeautifulSoup的安装u003c/liu003enu003c/ulu003enu003cpreu003eu003ccodeu003epip install beautifulsoup4nu003c/codeu003eu003c/preu003enu003culu003enu003cliu003elxml的安装u003c/liu003enu003c/ulu003enu003cpreu003eu003ccodeu003epip install lxmlnu003c/codeu003eu003c/preu003enu003cpu003e不报错即为安装成功u003c/pu003enu003cpu003eu003ca href="https://www.crummy.com/software/BeautifulSoup/bs4/doc/" target="_blank" rel="nofollow"u003eBeautifulSoup官方文档传送门u003c/au003eu003c/pu003enu003ch5u003e安装完上面三个包后,就开始制作我们的第一个小爬虫吧u003c/h5u003enu003cpu003e我们先来分析一下我们这次要爬取数据的网站数据。可以使用chrome浏览器自带的工具来抓包,按F12,选择Network,就可以看到所有的请求内容了。当然也可以用Fiddler这个优秀的工具来抓包,还能对请求进行截获并修改参数,大家有时间的话可以去玩一玩。这儿因为方便,我就采用了chrome浏览器自带的来进行分析了。u003c/pu003enu003cdiv class="image-package"u003enu003cdiv class="image-container" style="max-width: 700px; max-height: 687px;"u003enu003cdiv class="image-container-fill" style="padding-bottom: 65.86999999999999%;"u003eu003c/divu003enu003cdiv class="image-view" data-width="1043" data-height="687"u003eu003cimg data-original-src="//upload-images.jianshu.io/upload_images/2229106-84ee29373c54bd33.png" data-original-width="1043" data-original-height="687" data-original-format="image/png" data-original-filesize="85503"u003eu003c/divu003enu003c/divu003enu003cdiv class="image-caption"u003eu003c/divu003enu003c/divu003enu003cpu003e根据这个请求,我们能看出这个是一个GET请求。我们将headers里的内容绑定到类的属性里,接着绑定一个请求的地址。u003c/pu003enu003cpreu003eu003ccodeu003eimport requests #导入requests 模块nfrom bs4 import BeautifulSoup #导入BeautifulSoup 模块nn# 爬取文章案例编号和当前周期有效阅读数nclass BeautifulGetCaseSN():n def __init__(self): #类的初始化操作n #头部信息n self.headers = {n 'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0',n 'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',n 'Accept-Language':'zh-CN,zh;q=0.8',n 'Connection':'keep-alive',n 'Cookie':'JSESSIONID=48A82C60BE65ED14C5978297C03AF776; PHPSESSID=ST-10-QybrBt31XVfPBqKAT2jr'n } n #要访问的网页地址n self.web_url = 'http://net.chinamobile.com/cmccnkms-case/web/casesPortal/getCaseInfor.action?caseId=75058' nu003c/codeu003eu003c/preu003enu003cpu003e接下来我们再来分析一下要爬取的内容,下图中的三个框是我们要爬取的目标内容,分别是标题,当前周期有效阅读数,案例编号。u003c/pu003enu003cdiv class="image-package"u003enu003cdiv class="image-container" style="max-width: 700px; max-height: 563px;"u003enu003cdiv class="image-container-fill" style="padding-bottom: 80.47%;"u003eu003c/divu003enu003cdiv class="image-view" data-width="942" data-height="758"u003eu003cimg data-original-src="//upload-images.jianshu.io/upload_images/2229106-c96aeb0b24f92438.png" data-original-width="942" data-original-height="758" data-original-format="image/png" data-original-filesize="58469"u003eu003c/divu003enu003c/divu003enu003cdiv class="image-caption"u003eu003c/divu003enu003c/divu003enu003cpu003e分别右击审查元素,分析一下HTML的结构,以方便用BeautifulSoup来解析。u003c/pu003enu003cdiv class="image-package"u003enu003cdiv class="image-container" style="max-width: 564px; max-height: 301px;"u003enu003cdiv class="image-container-fill" style="padding-bottom: 53.37%;"u003eu003c/divu003enu003cdiv class="image-view" data-width="564" data-height="301"u003eu003cimg data-original-src="//upload-images.jianshu.io/upload_images/2229106-6c15551522d9f358.png" data-original-width="564" data-original-height="301" data-original-format="image/png" data-original-filesize="23906"u003eu003c/divu003enu003c/divu003enu003cdiv class="image-caption"u003eu003c/divu003enu003c/divu003enu003cdiv class="image-package"u003enu003cdiv class="image-container" style="max-width: 517px; max-height: 293px;"u003enu003cdiv class="image-container-fill" style="padding-bottom: 56.67%;"u003eu003c/divu003enu003cdiv class="image-view" data-width="517" data-height="293"u003eu003cimg data-original-src="//upload-images.jianshu.io/upload_images/2229106-b45919b7fb2c6254.png" data-original-width="517" data-original-height="293" data-original-format="image/png" data-original-filesize="15679"u003eu003c/divu003enu003c/divu003enu003cdiv class="image-caption"u003eu003c/divu003enu003c/divu003enu003cpu003e看了一遍这个网页的HTML,发现写这个网站的人真的是随意发挥,哈哈哈,都是直接用标签对的,标签class属性或者id属性几乎都没有,还好我们现在有了神器Beautifulsoup再手,根本不用愁无从下手这种的事儿。u003c/pu003enu003cpu003e通过分析,我们发现标题和当前有效周期的父级标签都是u003ccodeu003eu0026lt;td width=“78%”u0026gt;u003c/codeu003e,而且我搜索了下,发现u003ccodeu003ewidth=“78%”u003c/codeu003e属性只有这两个标签有。那么好办了,利用Beautifulsoup能对CSS属性解析的特性,我们就从这个属性下手。接着通过对案例编号的分析,我们发现这个u003ccodeu003eu0026lt;td class=“txleft”u0026gt;u003c/codeu003e标签有一个class属性,那就根据这个属性进行获取。u003c/pu003enu003cpreu003eu003ccodeu003edef get_data(self):n print('开始文章基础信息GET请求')n r = requests.get(self.web_url, headers=self.headers)n all_soup = BeautifulSoup(r.text, 'lxml')nn caseSn = all_soup.find_all('td','txleft') #案例编号抓取n print(caseSn[2].text)nn all_a = all_soup.find_all('td',width='78%')n title = all_a[0].find('h4').text #标题抓取n print(title)nn read_num = all_a[1].find_all('span')n print(read_num[3].text) #有效阅读数抓取nu003c/codeu003eu003c/preu003enu003cpu003eu003cstrongu003e解释一下这段代码:u003c/strongu003eu003c/pu003enu003cpreu003eu003ccodeu003er = requests.get(self.web_url, headers=self.headers)nall_soup = BeautifulSoup(r.text, 'lxml')nu003c/codeu003eu003c/preu003enu003cpu003e对网站进行GET请求,GET请求需要的参数有请求地址和头部信息,然后将获取的文本放入BeautifulSoup进行解析。这儿顺带说一句,python语言真的是人生苦短啊,请求网址,解析网页2句话就能完成,简洁的不得了,当然这个BeautifulSoup我为了逻辑清楚分开写了,不然也是能用一句代码来完成的。u003c/pu003enu003cpreu003eu003ccodeu003ecaseSn = all_soup.find_all('td','txleft') #案例编号抓取nprint(caseSn[2].text)nu003c/codeu003eu003c/preu003enu003cpu003e解析获取所有class类名为u003ccodeu003etxleftu003c/codeu003e的td标签,然后发现我们需要的案例编号是在第三个tag中,获取这个tag的文本内容。u003c/pu003enu003cpreu003eu003ccodeu003eall_a = all_soup.find_all('td',width='78%')ntitle = all_a[0].find('h4').text #标题抓取nprint(title)nnread_num = all_a[1].find_all('span')nprint(read_num[3].text) #有效阅读数抓取nu003c/codeu003eu003c/preu003enu003cpu003e通过打断点的方式,我们可以看到解析获取所有宽度属性为u003ccodeu003e78%u003c/codeu003e的td标签,一共有2个tag集,再在第1个标签集中解析获取为h4的标签,这个全文只存在唯一的一个,所以就获取到了我们所需要的文章标题。有效阅读数获取同理,在第2个标签集继续中解析获取叫span的标签,有效阅读数的内容藏在第四个span标签中。u003c/pu003enu003cpu003e关于BeautifulSoup的u003ccodeu003efind_all()u003c/codeu003e和u003ccodeu003efind()u003c/codeu003e的官方使用说明:u003c/pu003enu003cblockquoteu003enu003cpu003efind_all(name, attrs, recursive, text, **kwargs)u003cbru003enfind_all()方法搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件.u003c/pu003enu003c/blockquoteu003enu003cblockquoteu003enu003cpu003efind( name , attrs , recursive , text , **kwargs )u003cbru003enfind_all() 方法将返回文档中符合条件的所有tag,尽管有时候我们只想得到一个结果.比如文档中只有一个u0026lt;bodyu0026gt;标签,那么使用 find_all() 方法来查找u0026lt;bodyu0026gt;标签就不太合适, 使用 find_all 方法并设置 limit=1 参数不如直接使用 find() 方法.u003c/pu003enu003c/blockquoteu003enu003cpu003e现在让我们来实例化一个爬虫,满怀憧憬的按下F5,让他跑起来。u003c/pu003enu003cpreu003eu003ccodeu003egetCaseSN = BeautifulGetCaseSN() #创建类的实例,根据caseId爬取文章基础信息ngetCaseSN.get_data()nprint('爬取具体信息over')nu003c/codeu003eu003c/preu003enu003cdiv class="image-package"u003enu003cdiv class="image-container" style="max-width: 373px; max-height: 136px;"u003enu003cdiv class="image-container-fill" style="padding-bottom: 36.46%;"u003eu003c/divu003enu003cdiv class="image-view" data-width="373" data-height="136"u003eu003cimg data-original-src="//upload-images.jianshu.io/upload_images/2229106-06c0d1150250b423.png" data-original-width="373" data-original-height="136" data-original-format="image/png" data-original-filesize="7270"u003eu003c/divu003enu003c/divu003enu003cdiv class="image-caption"u003eu003c/divu003enu003c/divu003enu003cpu003e在调试控制台里查看结果。u003cbru003en哇!爬取数据成功!第一个小爬虫诞生了。u003c/pu003enu003cpu003e然鹅!现在还不能开始庆祝,毕竟任务才进行到一半。接下来,我们根据需求,还需要爬取文章的评论者的名字做爬取统计。继续对网页进行分析。u003c/pu003enu003cdiv class="image-package"u003enu003cdiv class="image-container" style="max-width: 700px; max-height: 403px;"u003enu003cdiv class="image-container-fill" style="padding-bottom: 55.279999999999994%;"u003eu003c/divu003enu003cdiv class="image-view" data-width="729" data-height="403"u003eu003cimg data-original-src="//upload-images.jianshu.io/upload_images/2229106-abbbbf137108bd02.png" data-original-width="729" data-original-height="403" data-original-format="image/png" data-original-filesize="32280"u003eu003c/divu003enu003c/divu003enu003cdiv class="image-caption"u003eu003c/divu003enu003c/divu003enu003cpu003e需要对上图中的评论者姓名进行爬取,而且还需要做到翻页。u003c/pu003enu003cdiv class="image-package"u003enu003cdiv class="image-container" style="max-width: 685px; max-height: 585px;"u003enu003cdiv class="image-container-fill" style="padding-bottom: 85.39999999999999%;"u003eu003c/divu003enu003cdiv class="image-view" data-width="685" data-height="585"u003eu003cimg data-original-src="//upload-images.jianshu.io/upload_images/2229106-bf8ead76b3ba14e9.png" data-original-width="685" data-original-height="585" data-original-format="image/png" data-original-filesize="56695"u003eu003c/divu003enu003c/divu003enu003cdiv class="image-caption"u003eu003c/divu003enu003c/divu003enu003cpu003e通过对请求的分析,发现这个评论块是个独立的请求,然后加入到文章页面的u0026lt;frameu0026gt;标签块中。点进去发现这是个POST请求,带有Form数据。通过对数据分析,发现有3个元素,第一个是评论的排序方式,我们不用动他,第二个是页码,就是翻页的关键参数,第三个是文章的Id。u003c/pu003enu003cpu003eu003cstrongu003e开始构建POST请求u003c/strongu003eu003c/pu003enu003cpreu003eu003ccodeu003e# 爬取具体信息nclass BeautifulGetData():n def __init__(self): #类的初始化操作n self.headers = {n 'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0',n 'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',n 'Accept-Language':'zh-CN,zh;q=0.8',n 'Connection':'keep-alive',n 'Cookie':'JSESSIONID=48A82C60BE65ED14C5978297C03AF776; PHPSESSID=ST-10-QybrBt31XVfPBqKAT2jr''n }n #要访问的网页地址n self.web_url = 'http://net.chinamobile.com/cmccnkms-case/web/casesPortal/loadComments.action' nn def get_data(self):n print('开始文章评论内容POST请求')n print('具体评论获取\n')n for x in range(1,10):n #post请求的数据n web_data = {n 'sort':'desc',n 'pageNum':x,n 'caseId':75058n }n r = requests.post(self.web_url,data=web_data, headers=self.headers)nu003c/codeu003eu003c/preu003enu003cpu003e这里增加一个for循环就是为了模拟请求的页码,根据pageNum的不同,对该网址进行多次请求获取不同页面信息。u003c/pu003enu003cdiv class="image-package"u003enu003cdiv class="image-container" style="max-width: 440px; max-height: 183px;"u003enu003cdiv class="image-container-fill" style="padding-bottom: 41.589999999999996%;"u003eu003c/divu003enu003cdiv class="image-view" data-width="440" data-height="183"u003eu003cimg data-original-src="//upload-images.jianshu.io/upload_images/2229106-debcd6a66b3d1a33.png" data-original-width="440" data-original-height="183" data-original-format="image/png" data-original-filesize="12154"u003eu003c/divu003enu003c/divu003enu003cdiv class="image-caption"u003eu003c/divu003enu003c/divu003enu003cpu003e通过分析评论页的HTML数据,我发现每个评论都用u0026lt;div class=“month”u0026gt;包含,于是我们可以用u003ccodeu003efind_allu003c/codeu003e来获取全部的这个class,因为每页都有五个评论,所以可以用for循环来进行分析并输出。u003c/pu003enu003cpu003eu003cstrongu003e下面是完整的请求代码u003c/strongu003eu003c/pu003enu003cpreu003eu003ccodeu003edef get_data(self):n print('开始文章评论内容POST请求')n print('具体评论获取\n')n get_name = []n get_next_name = []n for x in range(1,10):n web_data = {n 'sort':'desc',n 'pageNum':x,n 'caseId':75058n }n r = requests.post(self.web_url,data=web_data, headers=self.headers)n all_a = BeautifulSoup(r.text, 'lxml').find_all('div','month')n print('第',x,'页') n n #将上页获取的评论记录并清空当前页n get_name = get_next_namen get_next_name = []nn for a in enumerate(all_a): n str_name = a[1].text.split(':') #对获取的文本内容做切割n get_next_name.append(str_name[0]) #将名字加入到当前获取记录中n n if get_name == get_next_name:n print('完成')n breakn else:n for a in get_next_name:n print(a)nu003c/codeu003eu003c/preu003enu003cpu003e这里说一下我定义的两个list:u003ccodeu003eget_nameu003c/codeu003e和u003ccodeu003eget_next_nameu003c/codeu003e。之所以定义这两个是因为每篇文章的评论数量我是不知道的,所以我不能直接控制需要爬取的页数,只能尽可能大的写一个数。但是当页数小于我设定的页码值后会发生如下的数据重复显示事件。u003c/pu003enu003cdiv class="image-package"u003enu003cdiv class="image-container" style="max-width: 263px; max-height: 458px;"u003enu003cdiv class="image-container-fill" style="padding-bottom: 174.14000000000001%;"u003eu003c/divu003enu003cdiv class="image-view" data-width="263" data-height="458"u003eu003cimg data-original-src="//upload-images.jianshu.io/upload_images/2229106-567c4835fed9fe1a.png" data-original-width="263" data-original-height="458" data-original-format="image/png" data-original-filesize="7731"u003eu003c/divu003enu003c/divu003enu003cdiv class="image-caption"u003eu003c/divu003enu003c/divu003enu003cpu003e于是我加入了这两个参数,来存放前一页的获取的数据,如果单页获取的数据与前一页获取的数据相同,那说明就是到了评论的最后一页,直接跳出循环,结束该篇文章的评论爬取。u003c/pu003enu003cpu003e好了,把这两个类实例化一下,然后开始run起来吧。u003c/pu003enu003cpreu003eu003ccodeu003egetCaseSN = BeautifulGetCaseSN() #创建类的实例,根据caseId爬取文章基础信息ngetData = BeautifulGetData() #创建类的实例,根据caseId爬取文章评论信息ngetCaseSN.get_data()ngetData.get_data()nu003c/codeu003eu003c/preu003enu003cdiv class="image-package"u003enu003cdiv class="image-container" style="max-width: 374px; max-height: 356px;"u003enu003cdiv class="image-container-fill" style="padding-bottom: 95.19%;"u003eu003c/divu003enu003cdiv class="image-view" data-width="374" data-height="356"u003eu003cimg data-original-src="//upload-images.jianshu.io/upload_images/2229106-3f7bac68295028fc.png" data-original-width="374" data-original-height="356" data-original-format="image/png" data-original-filesize="9908"u003eu003c/divu003enu003c/divu003enu003cdiv class="image-caption"u003eu003c/divu003enu003c/divu003enu003cpu003e成功获取到了我希望得到的目标数据,完美!u003c/pu003enu003ch5u003e后记u003c/h5u003enu003cpu003e但是,只对一篇固定文章的爬取,远远不是我的最终目的,我的目的是,导入一份需要爬取的表格,然后进行自动的爬取,并将获取的数据输出并保存下来。在下一篇文章中,我就来讲一讲,Excel文件的导入读取与文件的导出保存。u003c/pu003en","voted_down":false,"rewardable":true,"show_paid_comment_tips":false,"share_image_url":"http://upload-images.jianshu.io/upload_images/2229106-84ee29373c54bd33.png","slug":"74f0b0edc94c","user":{"liked_by_user":false,"following_count":236,"gender":0,"avatar_widget":null,"slug":"8913ab3485de","intro":"","likes_count":358,"nickname":"杳杳靈鳯","badges":[],"total_fp_amount":"31323790081775595900","wordage":10537,"avatar":"https://upload.jianshu.io/users/upload_avatars/2229106/deebd7e9d5c3","id":2229106,"liked_user":false},"likes_count":60,"paid_type":"free","show_ads":true,"paid_content_accessible":false,"total_fp_amount":"1750000000000000000","trial_open":false,"reprintable":true,"bookmarked":false,"wordage":2130,"featured_comments_count":0,"downvotes_count":0,"wangxin_trial_open":null,"guideShow":{"audit_user_nickname_spliter":0,"pc_note_bottom_btn":1,"pc_like_author_guidance":0,"ban_some_labels":1,"audit_user_background_image_spliter":0,"audit_note_spliter":0,"launch_tab":0,"include_post":0,"pc_login_guidance":1,"audit_comment_spliter":1,"recommend_reason":1,"pc_note_bottom_qrcode":0,"audit_user_avatar_spliter":0,"audit_collection_spliter":0,"subscription_guide_entry":1,"creation_muti_function_on":1,"explore_score_searcher":1,"audit_user_spliter":1,"pc_note_popup":0},"commentable":true,"total_rewards_count":1,"id":34127616,"notebook":{"name":""},"activity_collection_slug":null,"description":"写出你的第一个小爬虫 在上一篇文章中对Python有了一定的基础学习后,我们现在要开始对网页进行爬取啦。 这次我们要爬取的网站是中国移动集团的运维案例文章和评论内容。这篇文章...","first_shared_at":1537367944,"views_count":3480,"notebook_id":29570537},"baseList":{"likeList":[],"rewardList":[]},"status":"success","statusCode":0},"user":{"isLogin":false,"userInfo":{}},"comments":{"list":[],"featuredList":[]}},"initialProps":{"pageProps":{"query":{"slug":"74f0b0edc94c"}},"localeData":{"common":{"jianshu":"简书","diamond":"简书钻","totalAssets":"总资产{num}","diamondValue":" (约{num}元)","login":"登录","logout":"注销","register":"注册","on":"开","off":"关","follow":"关注","followBook":"关注连载","following":"已关注","cancelFollow":"取消关注","publish":"发布","wordage":"字数","audio":"音频","read":"阅读","reward":"赞赏","zan":"赞","comment":"评论","expand":"展开","prevPage":"上一页","nextPage":"下一页","floor":"楼","confirm":"确定","delete":"删除","report":"举报","fontSong":"宋体","fontBlack":"黑体","chs":"简体","cht":"繁体","jianChat":"简信","postRequest":"投稿请求","likeAndZan":"喜欢和赞","rewardAndPay":"赞赏和付费","home":"我的主页","markedNotes":"收藏的文章","likedNotes":"喜欢的文章","paidThings":"已购内容","wallet":"我的钱包","setting":"设置","feedback":"帮助与反馈","loading":"加载中...","needLogin":"请登录后进行操作","trialing":"文章正在审核中...","reprintTip":"禁止转载,如需转载请通过简信或评论联系作者。"},"error":{"rewardSelf":"无法打赏自己的文章哟~"},"message":{"paidNoteTip":"付费购买后才可以参与评论哦","CommentDisableTip":"作者关闭了评论功能","contentCanNotEmptyTip":"回复内容不能为空","addComment":"评论发布成功","deleteComment":"评论删除成功","likeComment":"评论点赞成功","setReadMode":"阅读模式设置成功","setFontType":"字体设置成功","setLocale":"显示语言设置成功","follow":"关注成功","cancelFollow":"取消关注成功","copySuccess":"复制代码成功"},"header":{"homePage":"首页","download":"下载APP","discover":"发现","message":"消息","reward":"赞赏支持","editNote":"编辑文章","writeNote":"写文章"},"note":{},"noteMeta":{"lastModified":"最后编辑于 ","wordage":"字数 {num}","viewsCount":"阅读 {num}"},"divider":{"selfText":"以下内容为付费内容,定价 ¥{price}","paidText":"已付费,可查看以下内容","notPaidText":"还有 {percent} 的精彩内容","modify":"点击修改"},"paidPanel":{"buyNote":"支付 ¥{price} 继续阅读","buyBook":"立即拿下 ¥{price}","freeTitle":"该作品为付费连载","freeText":"购买即可永久获取连载内的所有内容,包括将来更新的内容","paidTitle":"还没看够?拿下整部连载!","paidText":"永久获得连载内的所有内容, 包括将来更新的内容"},"book":{"last":"已是最后","lookCatalog":"查看连载目录","header":"文章来自以下连载"},"action":{"like":"{num}人点赞","collection":"收入专题","report":"举报文章"},"comment":{"allComments":"全部评论","featuredComments":"精彩评论","closed":"评论已关闭","close":"关闭评论","open":"打开评论","desc":"按时间倒序","asc":"按时间正序","disableText1":"用户已关闭评论,","disableText2":"与Ta简信交流","placeholder":"写下你的评论...","publish":"发表","create":" 添加新评论","reply":" 回复","restComments":"还有{num}条评论,","expandImage":"展开剩余{num}张图","deleteText":"确定要删除评论么?"},"collection":{"title":"被以下专题收入,发现更多相似内容","putToMyCollection":"收入我的专题"},"seoList":{"title":"推荐阅读","more":"更多精彩内容"},"sideList":{"title":"推荐阅读"},"wxShareModal":{"desc":"打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮"},"bookChapterModal":{"try":"试读","toggle":"切换顺序"},"collectionModal":{"title":"收入到我管理的专题","search":"搜索我管理的专题","newCollection":"新建专题","create":"创建","nothingFound":"未找到相关专题","loadMore":"展开查看更多"},"contributeModal":{"search":"搜索专题投稿","newCollection":"新建专题","addNewOne":"去新建一个","nothingFound":"未找到相关专题","loadMore":"展开查看更多","managed":"我管理的专题","recommend":"推荐专题"},"QRCodeShow":{"payTitle":"微信扫码支付","payText":"支付金额"},"rewardModal":{"title":"给作者送糖","custom":"自定义","placeholder":"给Ta留言...","choose":"选择支付方式","balance":"简书余额","tooltip":"网站该功能暂时下线,如需使用,请到简书App操作","confirm":"确认支付","success":"赞赏成功"},"payModal":{"payBook":"购买连载","payNote":"购买文章","promotion":"优惠券","promotionFetching":"优惠券获取中...","noPromotion":"无可用优惠券","promotionNum":"{num}张可用","noUsePromotion":"不使用优惠券","validPromotion":"可用优惠券","invalidPromotion":"不可用优惠券","total":"支付总额","tip1":"· 你将购买的商品为虚拟内容服务,购买后不支持退订、转让、退换,请斟酌确认。","tip2":"· 购买后可在“已购内容”中查看和使用。","success":"购买成功"},"reportModal":{"ad":"广告及垃圾信息","plagiarism":"抄袭或未授权转载","placeholder":"写下举报的详情情况(选填)","success":"举报成功"},"guidModal":{"modalAText":"相似文章推荐","subText":"下载简书APP,浏览更多相似文章","btnAText":"先不下载,下次再说","followOkText":"关注作者成功!","followTextTip":"下载简书APP,作者更多精彩内容更新及时提醒!","followBtn":"下次再说","downloadTipText":"更多精彩内容下载简书APP","footerDownLoadText":"下载简书APP","modabTitle":"免费送你2次抽奖机会","modalbTip":"你有很大概率抽取AirPods Pro","modalbFooterTip":"下载简书APP,天天参与抽大奖","modalReward":"抽奖","scanQrtip":"扫码下载简书APP","downloadAppText":"下载简书APP,随时随地发现和创作内容","redText":"阅读","likesText":"赞","downLoadLeft":"下载App"}},"currentLocale":"zh-CN","asPath":"/p/74f0b0edc94c"}},"page":"/p/[slug]","query":{"slug":"74f0b0edc94c"},"buildId":"u2bo4IW2hHO5mrSY24vYe","assetPrefix":"https://cdn2.jianshu.io/shakespeare"}

文章来源于互联网:手把手系列:用Python3+PyQt5做一个有界面的小爬虫(二)

发表评论