GitOPEN's Home.

《手把手带你学爬虫──初级篇》第3课 Beautiful Soup 4 库讲解

Word count: 5,227 / Reading time: 25 min
2018/09/14 Share

本教程所有源码下载链接:https://share.weiyun.com/5xmFeUO 密码:fzwh6g

Beautiful Soup 4 库讲解

简介与安装

Beautiful Soup 4 库它是一个从HTML或者XML文件中提取数据的Python库。使用它,将极大地简化从网页源码中提取数据的步骤。

一个HTML或者XML文档就是一个标签树,使用bs4后,一个标签树就是一个BeautifulSoup类。

Beautiful Soup 4 库的安装:

1
pip install beautifulsoup4

Beautiful Soup 4 库基本使用方法

初体验

我们在ipython环境中体验一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
In [1]: import requests
In [2]: r = requests.get("https://raw.githubusercontent.com/opengit/CrawlerLessons/master/codes/lesson03/bs4_demo01.html")
In [3]: r.text
Out[3]: '<!DOCTYPE html>\n<html>\n\n<head>\n <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">\n <title>VPS推荐</title>\n</head>\n\n<body>\n<p class="title">\n <b>亲测速度很快</b>\n</p>\n<p class="links">\n 下面是两个推荐的VPS服务器链接:\n <a href="https://m.do.co/c/fd128f8ba9e8" class="vps1" id="link1">Digital Ocean优惠链接</a> 和\n <a href="https://www.vultr.com/?ref=7147564" class="vps2" id="link2">Vultr优惠10美元链接</a>。\n</p>\n</body>\n</html>'
In [4]: demo = r.text
In [5]: from bs4 import BeautifulSoup
In [6]: soup = BeautifulSoup(demo, "html.parser")
In [7]: print(soup.prettify())
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
<title>
VPS推荐
</title>
</head>
<body>
<p class="title">
<b>
亲测速度很快
</b>
</p>
<p class="links">
下面是两个推荐的VPS服务器链接:
<a class="vps1" href="https://m.do.co/c/fd128f8ba9e8" id="link1">
Digital Ocean优惠链接
</a>

<a class="vps2" href="https://www.vultr.com/?ref=7147564" id="link2">
Vultr优惠10美元链接
</a>

</p>
</body>
</html>

总结一下Beautiful Soup 4的最简单用法:

1
2
3
4
# 导入Beautiful Soup 4
from bs4 import BeautifulSoup
# 第1个参数是html文档内容,第2个参数是解析器
soup = BeautifulSoup(demo, "html.parser")

这里的html.parser是html解析器,有关解析器的用法,我们在后面讲解。

Beautiful Soup 4 库的元素

Beautiful Soup类的基本元素

1
2
3
<p class="title">
<b>亲测速度很快</b>
</p>
  • <p>...</p> 叫做标签Tag
  • p叫做标签的Name
  • class="title"叫做属性域
  • class叫做属性的Name
  • title叫做属性的值
基本元素 含义
Tag 标签,最基本的单元,用<></>标明开头和结尾
Name 标签名字,<a></a>的名字是a,用法:<tag>.name
Attributes 标签属性,字典形式,用法:<tag>.attrs
NavigableString 标签内非属性字符串,<>...</>中的字符串,用法:<tag>.string
Comment 标签内字符串的注释部分

ipython环境下,使用这些类的基本元素:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# 导入 Beautiful Soup 4
In [1]: from bs4 import BeautifulSoup
# 导入 requests
In [2]: import requests
# get请求网页
In [3]: r = requests.get("https://raw.githubusercontent.com/opengit/CrawlerLessons/master/codes/lesson03/bs4_demo01.html")

# html文本内容
In [4]: demo = r.text
# 拿到BeautifulSoup的对象
In [5]: soup = BeautifulSoup(demo, "html.parser")
# 获取a标签的名称
In [6]: soup.a.name
Out[6]: 'a'
# 获取a标签的父标签的名字
In [7]: soup.a.parent.name
Out[7]: 'p'
# 获取a标签的父标签的父标签的名字
In [8]: soup.a.parent.parent.name
Out[8]: 'body'
# soup.a的类型是Tag
In [9]: tag = soup.a
# 类型为Tag的a标签的属性
In [10]: tag.attrs
Out[10]: {'href': 'https://m.do.co/c/fd128f8ba9e8', 'class': ['vps1'], 'id': 'link1'}
# 取标签的属性值
In [11]: tag.attrs['class']
Out[11]: ['vps1']
In [12]: tag.attrs['href']
Out[12]: 'https://m.do.co/c/fd128f8ba9e8'
# Tag的属性返回的是一个字典类型
In [13]: type(tag.attrs)
Out[13]: dict
# soup.a 是一个Tag类型
In [14]: type(tag)
Out[14]: bs4.element.Tag
In [15]: tag
Out[15]: <a class="vps1" href="https://m.do.co/c/fd128f8ba9e8" id="link1">Digital Ocean优惠链接</a>
# 标签中的字符串
In [16]: tag.string
Out[16]: 'Digital Ocean优惠链接'
In [17]: soup.p
Out[17]:
<p class="title">
<b>亲测速度很快</b>
</p>
In [18]: soup.p.string
In [19]: soup.p.b.string
Out[19]: '亲测速度很快'
In [20]: type(soup.p.b.string)
# 标签中的字符串是NavigableString类型
Out[20]: bs4.element.NavigableString

# Comment 示例
In [25]: newsoup = BeautifulSoup("<b><!--我是注释--></b><p>我是注释</p>","html.parser")
In [26]: newsoup.b.string
Out[26]: '我是注释'
In [27]: type(newsoup.b.string)
Out[27]: bs4.element.Comment
In [29]: newsoup.p.string
Out[29]: '我是注释'
In [30]: type(newsoup.p.string)
Out[30]: bs4.element.NavigableString

Beautiful Soup 4 库的解析器

解析器 使用方法 优势 劣势 条件
Python标准库 BeautifulSoup(markup, "html.parser") Python的内置标准库执行速度适中文档容错能力强 Python 2.7.3 or 3.2.2)前的版本中文档容错能力差 直接使用
lxml HTML 解析器 BeautifulSoup(markup, "lxml") 速度快文档容错能力强 需要安装C语言库 pip install lxml
lxml XML 解析器 BeautifulSoup(markup, ["lxml", "xml"])BeautifulSoup(markup, "xml") 速度快唯一支持XML的解析器 需要安装C语言库 pip install lxml
html5lib BeautifulSoup(markup, "html5lib") 最好的容错性以浏览器的方式解析文档生成HTML5格式的文档 速度慢不依赖外部扩展 pip install html5lib

Beautiful Soup 4 库对HTML内容进行遍历

HTML基本格式

事实上,HTML的基本格式是一种树形结构/标签树。上面的例子中,使用的html的结构如图:

下行遍历

所谓下行遍历,就是从父节点向子节点进行遍历的方法。Beautiful Soup 4中有这个属性可以用在下行遍历中:

属性 含义
.contents 子节点的列表,是列表类型,将<tag>的所有子节点存入列表
.children 迭代类型,包含了所有子节点,可用于遍历循环子节点
.descendants 迭代类型,包含了所有子孙节点,用于遍历循环

下面在ipython中测试一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
In [33]: r = requests.get("https://raw.githubusercontent.com/opengit/CrawlerLessons/master/codes/lesson03/bs4_demo01.html")
In [34]: demo = r.text
In [35]: soup = BeautifulSoup(demo, "html.parser")
In [36]: soup.head
Out[36]: <head><meta content="text/html; charset=utf-8" http-equiv="Content-Type"/><title>VPS推荐</title></head>

# head标签的子节点列表
In [37]: soup.head.contents
Out[37]:
[<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>,
<title>VPS推荐</title>]
# body标签的子节点列表
In [38]: body = soup.body.contents
In [39]: body
Out[39]:
[<p class="title"><b>亲测速度很快</b></p>,
<p class="links">下面是两个推荐的VPS服务器链接:<a class="vps1" href="https://m.do.co/c/fd128f8ba9e8" id="link1">Digital Ocean优惠链接</a> 和<a class="vps2" href="https://www.vultr.com/?ref=7147564" id="link2">Vultr优惠10美元链接</a>。</p>]

# body标签的子节点列表的长度
In [40]: len(body)
Out[40]: 2

# body的所有子孙节点的迭代类型generator
In [41]: bodys = soup.body.descendants
In [42]: bodys
Out[42]: <generator object descendants at 0x104e2c0a0>
# 遍历子孙节点
In [43]: for item in bodys:
...: print(item)
...:
<p class="title"><b>亲测速度很快</b></p>
<b>亲测速度很快</b>
亲测速度很快
<p class="links">下面是两个推荐的VPS服务器链接:<a class="vps1" href="https://m.do.co/c/fd128f8ba9e8" id="link1">Digital Ocean优惠链接</a> 和<a class="vps2" href="https://www.vultr.com/?ref=7147564" id="link2">Vultr优惠10美元链接</a>。</p>
下面是两个推荐的VPS服务器链接:
<a class="vps1" href="https://m.do.co/c/fd128f8ba9e8" id="link1">Digital Ocean优惠链接</a>
Digital Ocean优惠链接

<a class="vps2" href="https://www.vultr.com/?ref=7147564" id="link2">Vultr优惠10美元链接</a>
Vultr优惠10美元链接

# body标签的子节点迭代类型
In [44]: bodyc = soup.body.children
# 遍历
In [45]: for item in bodyc:
...: print(item)
...:
<p class="title"><b>亲测速度很快</b></p>
<p class="links">下面是两个推荐的VPS服务器链接:<a class="vps1" href="https://m.do.co/c/fd128f8ba9e8" id="link1">Digital Ocean优惠链接</a> 和<a class="vps2" href="https://www.vultr.com/?ref=7147564" id="link2">Vultr优惠10美元链接</a>。</p>

上行遍历

标签树从下往上进行遍历。上行遍历的几个属性:

属性 含义
.parent <tag>的父亲标签
.parents <tag>的先辈们标签的迭代类型,用于遍历循环

接着上面的例子,下面在ipython中进行测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
In [46]: soup.title.parent
Out[46]: <head><meta content="text/html; charset=utf-8" http-equiv="Content-Type"/><title>VPS推荐</title></head>
# 由于html标签是最外层标签,因此html标签的父标签是它自己
In [47]: soup.html.parent
Out[47]:
<!DOCTYPE html>

<html><head><meta content="text/html; charset=utf-8" http-equiv="Content-Type"/><title>VPS推荐</title></head><body><p class="title"><b>亲测速度很快</b></p><p class="links">下面是两个推荐的VPS服务器链接:<a class="vps1" href="https://m.do.co/c/fd128f8ba9e8" id="link1">Digital Ocean优惠链接</a> 和<a class="vps2" href="https://www.vultr.com/?ref=7147564" id="link2">Vultr优惠10美元链接</a>。</p></body></html>
# soup的父标签为空
In [48]: soup.parent
# 遍历
In [49]: for item in soup.html.parents:
...: print(item)
...:
<!DOCTYPE html>

<html><head><meta content="text/html; charset=utf-8" http-equiv="Content-Type"/><title>VPS推荐</title></head><body><p class="title"><b>亲测速度很快</b></p><p class="links">下面是两个推荐的VPS服务器链接:<a class="vps1" href="https://m.do.co/c/fd128f8ba9e8" id="link1">Digital Ocean优惠链接</a> 和<a class="vps2" href="https://www.vultr.com/?ref=7147564" id="link2">Vultr优惠10美元链接</a>。</p></body></html>

平行遍历

前提:参与平行遍历的节点必须拥有同一个父亲节点

属性 含义
.next_sibling 返回按照HTML文本顺序的下一个平行节点标签
.previous_sibling 返回按照HTML文本顺序的上一个平行节点标签
.next_siblings 迭代类型,返回按照HTML文本顺序的后续所有平行节点标签
.previous_siblings 迭代类型,返回按照HTML文本顺序的前续所有平行节点标签

ipython中使用这些属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
In [50]: soup.body.contents
Out[50]:
[<p class="title"><b>亲测速度很快</b></p>,
<p class="links">下面是两个推荐的VPS服务器链接:<a class="vps1" href="https://m.do.co/c/fd128f8ba9e8" id="link1">Digital Ocean优惠链接</a> 和<a class="vps2" href="https://www.vultr.com/?ref=7147564" id="link2">Vultr优惠10美元链接</a>。</p>]

In [51]: soup.body.contents[0].next_sibling
Out[51]: <p class="links">下面是两个推荐的VPS服务器链接:<a class="vps1" href="https://m.do.co/c/fd128f8ba9e8" id="link1">Digital Ocean优惠链接</a> 和<a class="vps2" href="https://www.vultr.com/?ref=7147564" id="link2">Vultr优惠10美元链接</a>。</p>

In [52]: soup.body.contents[1].next_sibling

In [53]: soup.body.contents[1].previous_sibling
Out[53]: <p class="title"><b>亲测速度很快</b></p>

In [54]: soup.a.next_sibling
Out[54]: ' 和'

In [55]: soup.a.next_sibling.next_sibling
Out[55]: <a class="vps2" href="https://www.vultr.com/?ref=7147564" id="link2">Vultr优惠10美元链接</a>

In [56]: soup.a.previousSibling
Out[56]: '下面是两个推荐的VPS服务器链接:'

In [57]: soup.a.previous_sibling
Out[57]: '下面是两个推荐的VPS服务器链接:'

In [58]: soup.a.previous_sibling.previousSibling

In [59]: soup.a.next_sibling.previous_sibling
Out[59]: <a class="vps1" href="https://m.do.co/c/fd128f8ba9e8" id="link1">Digital Ocean优惠链接</a>

Beautiful Soup 4 库对HTML格式化输出

也就是让输出的HTML更加好看。使用prettify()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
In [60]: r.text
Out[60]: '<!DOCTYPE html>\n<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>VPS推荐</title></head><body><p class="title"><b>亲测速度很快</b></p><p class="links">下面是两个推荐的VPS服务器链接:<a href="https://m.do.co/c/fd128f8ba9e8" class="vps1" id="link1">Digital Ocean优惠链接</a> 和<a href="https://www.vultr.com/?ref=7147564" class="vps2" id="link2">Vultr优惠10美元链接</a>。</p></body></html>'

In [61]: soup.prettify()
Out[61]: '<!DOCTYPE html>\n<html>\n <head>\n <meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>\n <title>\n VPS推荐\n </title>\n </head>\n <body>\n <p class="title">\n <b>\n 亲测速度很快\n </b>\n </p>\n <p class="links">\n 下面是两个推荐的VPS服务器链接:\n <a class="vps1" href="https://m.do.co/c/fd128f8ba9e8" id="link1">\n Digital Ocean优惠链接\n </a>\n 和\n <a class="vps2" href="https://www.vultr.com/?ref=7147564" id="link2">\n Vultr优惠10美元链接\n </a>\n 。\n </p>\n </body>\n</html>'

In [62]: print(soup.prettify())
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
<title>
VPS推荐
</title>
</head>
<body>
<p class="title">
<b>
亲测速度很快
</b>
</p>
<p class="links">
下面是两个推荐的VPS服务器链接:
<a class="vps1" href="https://m.do.co/c/fd128f8ba9e8" id="link1">
Digital Ocean优惠链接
</a>

<a class="vps2" href="https://www.vultr.com/?ref=7147564" id="link2">
Vultr优惠10美元链接
</a>

</p>
</body>
</html>

Beautiful Soup 4 库常用函数

<tag>.find_all(name, attrs, recursive, string, **kwargs)

返回一个列表类型,存储查找的结果。

name:标签名字检索字符串,可以为列表形式,包含多个检索字符串;

attrs:标签属性值的检索字符串,可标注属性检索;

recursive:是否对子孙节点全部检索,默认值是True;

string<>...</>中字符串区域的检索字符串;

**kwargs:;

ipython中进行测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
In [63]: for link in soup.find_all('a'):
...: print(link.get('href'))
...:
https://m.do.co/c/fd128f8ba9e8
https://www.vultr.com/?ref=7147564

In [64]: soup.find_all(['a','b'])
Out[64]:
[<b>亲测速度很快</b>,
<a class="vps1" href="https://m.do.co/c/fd128f8ba9e8" id="link1">Digital Ocean优惠链接</a>,
<a class="vps2" href="https://www.vultr.com/?ref=7147564" id="link2">Vultr优惠10美元链接</a>]

In [65]: for tag in soup.find_all(True):
...: print(tag.name)
...:
html
head
meta
title
body
p
b
p
a
a

# 利用正则表达式,打印出所有以b开头的标签名称
In [66]: import re

In [67]: for tag in soup.find_all(re.compile('b')):
...: print(tag.name)
...:
body
b

# 查找所有a标签,列表形式返回
In [72]: soup.find_all('a')
Out[72]:
[<a class="vps1" href="https://m.do.co/c/fd128f8ba9e8" id="link1">Digital Ocean优惠链接</a>,
<a class="vps2" href="https://www.vultr.com/?ref=7147564" id="link2">Vultr优惠10美元链接</a>]

# 查找所有a标签中,id='link1'的a标签,返回列表
In [73]: soup.find_all('a',id='link1')
Out[73]: [<a class="vps1" href="https://m.do.co/c/fd128f8ba9e8" id="link1">Digital Ocean优惠链接</a>]
# 查找所有a标签中,id='link2'的a标签,返回列表
In [74]: soup.find_all('a',id='link2')
Out[74]: [<a class="vps2" href="https://www.vultr.com/?ref=7147564" id="link2">Vultr优惠10美元链接</a>]
# 查找所有p标签中,id='link1'的a标签,返回列表,由于p标签没有带id='link1'的,所有列表中没有元素
In [75]: soup.find_all('p',id='link2')
Out[75]: []

# 输出所有id的值以link开头的标签
In [76]: soup.find_all(id=re.compile('link'))
Out[76]:
[<a class="vps1" href="https://m.do.co/c/fd128f8ba9e8" id="link1">Digital Ocean优惠链接</a>,
<a class="vps2" href="https://www.vultr.com/?ref=7147564" id="link2">Vultr优惠10美元链接</a>]

# 查找所有字符串中含有‘优惠’的字符串
In [78]: soup.find_all(string = re.compile('优惠'))
Out[78]: ['Digital Ocean优惠链接', 'Vultr优惠10美元链接']

下面介绍一下Beautiful Soup 4的其他方法:

函数名 含义 参数
<tag>.find() 返回字符串类型,搜索并返回一个结果 同find_all()参数
<tag>.find_parent() 返回字符串类型,在先辈中返回一个结果 同find()参数
<tag>.find_parents() 返回列表类型,在先辈中搜索 同find_all()参数
<tag>.find_next_sibling() 返回字符串类型,在后续平行节点中返回一个结果 同find()参数
<tag>.find_next_siblings() 返回列表类型,在后续平行节点中搜索 同find_all()参数
<tag>.find_previous_sibling() 返回字符串类型,在前续平行节点中返回一个结果 同find()参数
<tag>.find_previous_siblings() 返回列表类型,在前续平行节点中搜索 同find_all()参数

Beautiful Soup 4 库补充知识

  1. <tag>.string用法总结:

    • 如果tag只有一个NavigableString类型子节点(文本内容),那么将得到该子节点;
    • 如果tag只有一个子节点,那么.string得到的结果,和上面的结果一样;
    • 如果tag包含多个子节点,tag就无法确定.string方法该调用哪个节点的内容,因此结果是None。
  2. <tag>.strings<tag>.stripped_strings用法:

    • 如果tag中包含多个字符串,可以使用.strings来循环遍历,输出的字符串中可能包含很多空格或空行;
    • 使用.stripped_strings可以去除多余空白内容,全部是空格的行会被忽略掉,段首和段尾的空白会被删除。
  3. CSS选择器,Beautiful Soup 4 支持大部分的CSS选择器,在select()方法中传入字符串参数即可使用:

    #link1 是id选择器;.sister是class类选择器。

    • 通过tag标签逐层查找:

      1
      soup.select("body a")
    • 找到某个tag标签下的直接子标签:

      1
      2
      soup.select("head > title")
      soup.select("p > #link1")
    • 找到兄弟节点标签:

      1
      2
      3
      4
      # 找到所有兄弟节点
      soup.select("#link1 ~ .sister")
      # 找到下一个兄弟节点
      soup.select("#link1 + .sister")
    • 通过CSS的类名查找:

      1
      2
      soup.select(".sister")
      soup.select("[class~=sister]")
    • 通过tag的id查找:

      1
      2
      soup.select("#link1")
      soup.select("a#link2")
    • 通过是否存在某个属性查找:

      1
      soup.select('a[href]')
    • 通过属性的值来查找:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      soup.select('a[href="http://example.com/elsie"]')
      # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]

      # 属性的值开头含有某字符串
      soup.select('a[href^="http://example.com/"]')
      # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
      # <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
      # <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

      # 属性的值结尾含有某字符串
      soup.select('a[href$="tillie"]')
      # [<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

      # 属性的值中间含有某字符串
      soup.select('a[href*=".com/el"]')
      # [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
  4. <tag>.get_text()方法,如果只想得到tag中包含的文本内容,那么可以调用这个方法,获取到tag中包含的所有文本内容,包括子孙tag中的内容,并将结果作为Unicode字符串返回。

实战——用Beautiful Soup 4 库爬取豆瓣电影排行榜Top250

豆瓣电影Top250的页面地址是https://movie.douban.com/top250?start=0,打开页面以后,发现页面下方有页面页码导航,因此,访问不同页面的数据的策略就是更改`start=0`的值,每个页面25条数据。

本实战代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import json

import requests
from bs4 import BeautifulSoup

### 可以改进的地方:
### 我们拿到的数据是在列表中拿到的,并不完善;
### 我们的作业是,拿到电影详情url以后,访问该url,从页面中爬取更多的信息。

def get_html(url):
"""
获取网页源码
:param url: 网页请求链接
:return: 返回网页源码
"""
try:
r = requests.get(url, timeout=30)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except Exception as e:
print("产生了异常:{}".format(str(e)))


def parse_movie_by_bs4(html):
"""
处理网页源码,使用Beautiful Soup 4提取电影信息
:param html: 网页源码
:return: 当前页电影信息的列表
"""
# 列表形式,用以存储抽取出来的数据,每个数据是字典形式
page_movies = []

# 处理数据

# 1. 把html文档内容交给Beautiful Soup
soup = BeautifulSoup(html, "lxml")
# 2.查找所有class='info'的div节点
div_infos = soup.find_all('div', {'class': 'info'})
for div_info in div_infos:
# 用字典保存
movie = {}

# 3. 查找拥有class="hd"属性值的节点
div_hd = div_info.find('div', {'class': 'hd'})
# 4. 查找拥有class="bd"属性值的节点
div_bd = div_info.find('div', {'class': 'bd'})

# 5.从div_hd中取出url和title
movie['url'] = div_hd.a.attrs['href']
title = ''
for span in div_hd.a.contents:
title += str(span.string)
movie['title'] = ''.join(title.split())

# 6. 从div_bd中取出 导演(boss) 、主演(role)、年份(year)、国家(nation)、类别(category)、 引用评价(quote)
p1 = div_bd.find('p', {'class': ''})
movie['info'] = ",".join(p1.get_text(',', strip=True).split()).replace(":", ",").replace(",,", ",").replace("/,", "")

div_star = div_bd.find('div')
movie['rating_num'] = div_star.find_all('span')[1].string
movie['valuation_num'] = str(div_star.find_all('span')[3].string).replace("人评价", "")

p2 = div_bd.find('p', {'class': 'quote'})
if p2 is not None:
movie['quote'] = p2.span.string
else:
movie['quote'] = ""

page_movies.append(movie)

return page_movies


def main():
"""
控制url,循环爬取所有页面,得到所有电影信息
"""
bash_url = 'https://movie.douban.com/top250?start='
offset = 0
all_movies = []
page_id = 0
while offset < 250:
print("正在爬取第{}页".format(str(page_id + 1)))
url = bash_url + str(offset)
html_text = get_html(url)
page_movies = parse_movie_by_bs4(html_text)
all_movies.append(page_movies)
offset += 25
page_id += 1
with open("douban_250.json", "w") as filename:
filename.write(json.dumps(all_movies, ensure_ascii=False))
print("所有数据爬取完毕")


if __name__ == '__main__':
main()

参考资料推荐

官方文档:《Beautiful Soup 4.2.0 文档》


欣慰帮到你 一杯热咖啡
【奋斗的Coder!】企鹅群
【奋斗的Coder】公众号
CATALOG
  1. 1. Beautiful Soup 4 库讲解
  2. 2. 简介与安装
  3. 3. Beautiful Soup 4 库基本使用方法
    1. 3.1. 初体验
    2. 3.2. Beautiful Soup 4 库的元素
      1. 3.2.1. Beautiful Soup类的基本元素
    3. 3.3. Beautiful Soup 4 库的解析器
    4. 3.4. Beautiful Soup 4 库对HTML内容进行遍历
      1. 3.4.1. HTML基本格式
      2. 3.4.2. 下行遍历
      3. 3.4.3. 上行遍历
      4. 3.4.4. 平行遍历
    5. 3.5. Beautiful Soup 4 库对HTML格式化输出
    6. 3.6. Beautiful Soup 4 库常用函数
    7. 3.7. Beautiful Soup 4 库补充知识
  4. 4. 实战——用Beautiful Soup 4 库爬取豆瓣电影排行榜Top250
  5. 5. 参考资料推荐