Python学习笔记 - 爬虫基础之 bs4 数据解析模块及爬虫实例

bs4(Beautiful Soup 4.4.0) 是一个可以从HTML或XML文件中提取数据的Python库,其中的 BeautifulSoup类,可以用来获取html页面的内容,配合requests库可以构建简单的爬虫程序。

bs4是第三方库,需要手动安装。


一、bs4模块的基本使用方法

首先构建一个BeautifulSoup实例对象,传入Web页面的 html 文档内容(字符串格式)或 本地html 文件的句柄,传入所使用的解析器,然后就可以使用BeautifulSoup实例对象的属性和方法获取 html 文档中的相应数据了。

传入的 html 文档内容可以使用requests模块从网络中获取,也可以打开本地 html 文件进行读取,或者直接将本地 html 文件的句柄传给BeautifulSoup实例对象。

示例代码:

import requests
from bs4 import BeautifulSoup

# 使用requests模块获取Web页面的文档内容,创建BeautifulSoup实例对象
url = 'https://www.baidu.com'
resp = requests.get(url)
resp.encoding = 'utf-8'
html_doc = resp.text
soup1 = BeautifulSoup(html_doc, 'html.parser') 

# 打开并读取本地html文件内容,创建BeautifulSoup实例对象
with open('test.html', encoding='utf-8') as fin:
    html_doc = fin.read()
soup2 = BeautifulSoup(html_doc, 'html.parser')

# 直接传入本地html文件句柄,创建BeautifulSoup实例对象
soup3 = BeautifulSoup(open('test.html', encoding='utf-8'), 'html.parser')

print('soup1的网页标题是:', soup1.title.text)
print('soup2的网页标题是:', soup2.title.text)
print('soup3的网页标题是:', soup3.title.text)

运行结果:
soup1的网页标题是: 百度一下,你就知道
soup2的网页标题是: 测试网页
soup3的网页标题是: 测试网页

【注】上面示例代码中的html.parser,是创建BeautifulSoup实例对象时所使用的解析器。html.parser是Python自带的内置标准库,可以直接使用,另外还有第三方解析器,使用时需要手动安装。


二、解析器

Beautiful Soup 能够从 html 文档中解析出各种有用数据,例如网页标题、文本、链接等,依赖于强大的解析器。它支持Python标准库中的HTML解析器,还支持一些第三方的解析器,详细情况如下表:

解析器

调用方法

优势

劣势

Python标准库

"html.parser"

  • Python的内置标准库
  • 执行速度适中
  • 文档容错能力强
  • Python3.2.2之前版本的中文档容错能力差

lxml HTML 解析器

"lxml"

  • 速度快
  • 文档容错能力强
  • 需要安装C语言库

lxml XML 解析器

"lxml-xml"

  • 速度快
  • 唯一支持XML的解析器
  • 需要安装C语言库

html5lib


  • 最好的容错性
  • 以浏览器的方式解析文档
  • 生成HTML5格式的文档
  • 最好的容错性
  • 以浏览器的方式解析文档
  • 生成HTML5格式的文档

【注】以上解析器中,只有Python标准库不需要手动安装,可以直接使用"html.parser"的形式调用,其它解析器都是第三方库,需要手动安装,安装方法与其它第三方模块的安装方法相同。Python内置的"html.parser"解析器,在简单爬虫中最为常用。


三、常用属性和方法

为了方便演示和理解,我们首先创建一个html文档,然后针对该文档进行数据解析演示。

测试html文档(test.html)代码如下:



   
      
      测试网页
   
   
      

标题1链接

标题2

标题3

标题4

段落

百度
网易
爱奇艺
京东

1、text属性

text属性返回标签内或html文档的全部文本内容,内容为空则返回空字符

示例代码:

from bs4 import BeautifulSoup

# 打开并读取上面创建的html文件内容,创建BeautifulSoup实例对象
with open('test.html', encoding='utf-8') as fin:
    html_doc = fin.read()
soup = BeautifulSoup(html_doc, 'html.parser')

# 返回h1标签中的全部文本内容
print(soup.h1.text)

print('='*30)

# 返回整个html文档的全部文本内容
print(soup.text)

运行结果:
标题1链接 
==============================




测试网页


标题1链接 
标题2
标题3
标题4

段落
百度
网易
爱奇艺




2、string属性

string与text属性都是返回文本内容,但又有很大的不同。string属性返回的是标签内的文本内容,如果标签内的文本为空或者有多处文本,则返回None。

部分示例代码:

# 打印输出h1、h2和h5标签内的文本内容
print(soup.h1.string)
print(soup.h2.string)
print(soup.h5.string)

运行结果:
None
标题2
None

3、Tag标签对象属性

Tag标签对象对应 html 文档中的标签,可以返回 html 标签的相应内容

部分示例代码:

# 输出h1标签的内容
print(soup.h1)
# 输出h1标签的名称
print(soup.h1.name)
# 输出h1标签的文本内容
print(soup.h1.text)
# 输出a标签内的链接地址,只会输出html文档内的第一个a标签的内容
print(soup.a['href'])
# 输出p标签内的a标签的链接地址,第一个p里面的第一个a标签
print(soup.p.a['href'])

运行结果:

标题1链接

h1 标题1链接 test.html https://www.baidu.com

4、get_text()方法

get_text()方法的结果与text属性相同,即获取标签或整个文档的文本内容

部分示例代码:

# 输出网页标题文本内容
print(soup.title.getText())

运行结果:
测试网页

5、find()方法

find()方法是根据标签及标签中的属性值进行查找,通常用于爬虫中进行精确定位。

示例代码:

from bs4 import BeautifulSoup

# 打开并读取本地html文件内容,创建BeautifulSoup实例对象
with open('test.html', encoding='utf-8') as fin:
    html_doc = fin.read()
soup = BeautifulSoup(html_doc, 'html.parser')

# 查找h1标签
data = soup.find('h1')
print(data.text)

# 根据a标签的id属性查找
data = soup.find('a', id='link3')
print(data.text)

# 根据p标签的class属性查找,由于class是python的关键字,因此使用class_进行查找
data = soup.find('p', class_='default')
print(data.text)

运行结果:
标题1链接 
爱奇艺

段落
百度
网易
爱奇艺

6、find_all()方法

find_all()与find()方法的功能和使用方法基本相同,只是find_all()查找的是所有指定标签,返回一个结果集,可以通过循环进行遍历。find_all()方法也是实现批量爬取的总要手段。

示例代码:

from bs4 import BeautifulSoup

# 打开并读取本地html文件内容,创建BeautifulSoup实例对象
with open('test.html', encoding='utf-8') as fin:
    html_doc = fin.read()
soup = BeautifulSoup(html_doc, 'html.parser')

# 查找所有a标签,循环输出a标签的链接地址和文本内容
links = soup.find_all('a')
for link in links:
    print(link['href'], link.getText())

print('='*30)

# 先定位到p区块,再在该区块内查找,精确定位
p_node = soup.find('p', id='content')
img = p_node.find('img')
print(img['src'])

运行结果:
test.html 链接
https://www.baidu.com 百度
https://www.163.com 网易
https://www.iqiyi.com 爱奇艺
==============================
//img03.bs178.com/cd/ug/2c981ca37da0c32f.jpg

四、简单爬虫实例

(一)目标

链接地址:https://www.qidian.com/all/chanId21-subCateId8/

爬取上面链接地址的Web页面中的所有小说的标题以及对应的链接地址,输出到屏幕上

(二)网页内容分析

使用浏览器打开链接地址,在任意一个小说标题上点鼠标右键 检查,分屏中的代码会自动定位到该小说标题位置。经过观察分析可以确定,每个小说标题的最外层都由一对 li 标签包裹,再向里有一对class属性为'book-mid-info'的 p 标签,我们使用find_all()方法查找这个p标签,就可以获取所有的数据。如下图:

(三)实例代码

import requests
from bs4 import BeautifulSoup

url = 'https://www.qidian.com/all/chanId21-subCateId8/'
r = requests.get(url)
if r.status_code != 200:
    raise Exception()
html_doc = r.text

soup = BeautifulSoup(html_doc, 'html.parser')
p_nodes = soup.find_all('p', class_='book-mid-info')
for p_node in p_nodes:
    link = p_node.find('a')
    print(link.get_text(), 'https:' + link['href'])

运行结果:
道诡异仙 https://book.qidian.com/info/1031794030/
万古神帝 https://book.qidian.com/info/3546912/
乱世书 https://book.qidian.com/info/1036010291/
女侠且慢 https://book.qidian.com/info/1034840014/
万相之王 https://book.qidian.com/info/1027368101/
诸界第一因 https://book.qidian.com/info/1029701421/
当不成赘婿就只好命格成圣 https://book.qidian.com/info/1034730904/
开局签到荒古圣体 https://book.qidian.com/info/1021378513/
保护我方族长 https://book.qidian.com/info/1024121691/
帝霸 https://book.qidian.com/info/3258971/
最初进化 https://book.qidian.com/info/1017021237/
白骨大圣 https://book.qidian.com/info/1020884972/
猎命人 https://book.qidian.com/info/1032636821/
人族镇守使 https://book.qidian.com/info/1026225232/
我在聊天群模拟长生路 https://book.qidian.com/info/1035776910/
修炼从简化功法开始 https://book.qidian.com/info/1034284970/
神诡世界,我能修改命数 https://book.qidian.com/info/1031996546/
从肉体凡胎到粉碎星球 https://book.qidian.com/info/1036613110/
完美世界 https://book.qidian.com/info/2952453/
苟在东宫涨天赋,发现太子女儿身 https://book.qidian.com/info/1035677938/

五、进阶案例

(一)目标

链接地址:https://m.890h.com/10_10447/

爬取链接地址中小说的所有章节,每个章节使用标题为文件名保存成一个文本文件,共19章,即生成19个文本文件。

(二)网页内容分析

(三)爬虫代码分析

1、获取小说所有章节标题和链接的函数

由于我们本次要爬取的是小说的所有正文,因此第一步需要构建一个函数,用来获取小说的所有章节标题和正文链接地址。

函数代码如下:

def get_novel_chapters():
    root_url = 'https://m.890h.com/10_10447/'
    url_list = []
    resp = requests.get(root_url)
    resp.encoding = 'utf-8'
    if resp.status_code != 200:
        raise Exception('爬取小说目录时发生请求错误!')

    soup = BeautifulSoup(resp.text, 'html.parser')
    links = soup.find_all('p', class_='directoryArea')[1].find_all('a')

    for link in links:
        url_list.append(('https://m.890h.com' + link['href'], link.get_text()))
    return url_list

注释:

2、获取一个章节正文内容的函数

再创建一个函数,根据传入的链接地址,获取到链接中的正文内容,并将文本内容返回给函数。

函数代码如下:

def get_chapter_content(url):
    resp = requests.get(url)
    resp.encoding = 'utf-8'
    if resp.status_code != 200:
        raise Exception('爬取小说内容时发生请求错误!')
    soup = BeautifulSoup(resp.text, 'html.parser')
    return soup.find('p', id='chaptercontent').get_text()

3、主程序

在主程序中,首先使用第一个函数获取所有章节的链接地址和标题。遍历所有章节内容,使用小说标题创建同名文本文件,使用第二个函数获取每个章节的正文文本内容,并写入到文本文件中。

完整代码如下:

import requests
from bs4 import BeautifulSoup


# 获取小说所有章节标题和链接的函数
def get_novel_chapters():
    root_url = 'https://m.890h.com/10_10447/'
    url_list = []
    resp = requests.get(root_url)
    resp.encoding = 'utf-8'
    if resp.status_code != 200:
        raise Exception('爬取小说目录时发生请求错误!')
    soup = BeautifulSoup(resp.text, 'html.parser')
    links = soup.find_all('p', class_='directoryArea')[1].find_all('a')
    for link in links:
        url_list.append(('https://m.890h.com' + link['href'], link.get_text()))
    return url_list


# 获取一个章节正文内容的函数
def get_chapter_content(url):
    resp = requests.get(url)
    resp.encoding = 'utf-8'
    if resp.status_code != 200:
        raise Exception('爬取小说内容时发生请求错误!')
    soup = BeautifulSoup(resp.text, 'html.parser')
    return soup.find('p', id='chaptercontent').get_text()


# 主程序
if __name__ == '__main__':
    for chapter in get_novel_chapters():
        url, title = chapter
        print('正在爬取:', title)
        with open('%s.txt' % title, 'w', encoding='utf-8') as wfile:
            wfile.write(get_chapter_content(url))

运行结果:
正在爬取: 第一章 重生
正在爬取: 第二章 向家小姐
正在爬取: 第三章 救下美女
正在爬取: 第四章 苏珂的相亲
正在爬取: 第五章 你可以滚了
正在爬取: 第六章 我陪你玩
正在爬取: 第七章 等五分钟
正在爬取: 第八章 推拿按摩
正在爬取: 第九章 废物老公
正在爬取: 第十章 害怕的应该不是我
正在爬取: 第十一章 再见刀疤
正在爬取: 第十二章 不受恩惠
正在爬取: 第十三章 我等皆下等
正在爬取: 第十四章 向心雨的姐姐?
正在爬取: 第十五章 我真是路过
正在爬取: 第十六章 那个男生
正在爬取: 第十七章 枯木逢春
正在爬取: 第十八章 任何条件
正在爬取: 第十九章 解决了苏珂的事
正在爬取: 第十九章 何必逞强

【注】在屏幕输出提示信息的同时,在程序目录下生成了19个文本文件,就是小说的所有内容。

展开阅读全文

页面更新:2024-03-02

标签:爬虫   实例   模块   属性   文本   标签   代码   文档   链接   标题   网页   基础   内容   数据   小说

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top