06—小白学Python爬虫之BeautifulSoup入门与应用(以糗百为例)

之前介绍了通过正则和xpath来解析HTML文本,本篇将会介绍一种全新的方式BeautifulSoup来解析HTML,相对前两种使用更简单,那么,在介绍之前,先对这三种方式做一个简单的对比。

抓取方式速度使用难度安装难度
正则最快困难无(内置)
xpath简单一般
BeautifulSoup最简单简单

简介

概念

Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间。

安装
  1. Debain Ubuntu上安装
    如果你用的是新版的Debain或ubuntu,那么可以通过系统的软件包管理来安装:

    apt-get install Python-bs4
  2. pip安装
    Beautiful Soup 4 通过PyPi发布,所以如果你无法使用系统包管理安装,那么也可以通过 easy_installpip 来安装.包的名字是 beautifulsoup4 ,这个包兼容Python2和Python3.

    $ easy_install beautifulsoup4
    $ pip install beautifulsoup4

    如果直接使用pip install beautifulsoup安装的话,默认为bs3版本。

  3. 源码安装
    如果你没有安装 easy_installpip ,那你也可以 下载BS4的源码 ,然后通过setup.py来安装.

    Python setup.py install
  4. 打包安装
    如果上述安装方法都行不通,Beautiful Soup的发布协议允许你将BS4的代码打包在你的项目中,这样无须安装即可使用。
安装后问题

Beautiful Soup发布时打包成Python2版本的代码,在Python3环境下安装时,会自动转换成Python3的代码,如果没有一个安装的过程,那么代码就不会被转换.

如果代码抛出了 ImportError 的异常: No module named HTMLParser, 这是因为你在Python3版本中执行Python2版本的代码.

如果代码抛出了ImportError 的异常: No module named html.parser, 这是因为你在Python2版本中执行Python3版本的代码.

如果遇到上述2种情况,最好的解决方法是重新安装BeautifulSoup4.

如果在ROOT_TAG_NAME = u’[document]’代码处遇到 SyntaxError “Invalid syntax”错误,需要将把BS4的Python代码版本从Python2转换到Python3. 可以重新安装BS4:

Python3 setup.py install

或在bs4的目录中执行Python代码版本转换脚本

2to3-3.2 -w bs4
安装解析器

Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,其中一个是 lxml .根据操作系统不同,可以选择下列方法来安装lxml:

apt-get install Python-lxml
easy_install lxml
pip install lxml

另一个可供选择的解析器是纯Python实现的 html5lib , html5lib的解析方式与浏览器相同,可以选择下列方法来安装html5lib:

apt-get install Python-html5lib
easy_install html5lib
pip install html5lib

下表列出了主要的解析器,以及它们的优缺点:

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

推荐使用lxml作为解析器,因为效率更高. 在Python2.7.3之前的版本和Python3中3.2.2之前的版本,必须安装lxml或html5lib, 因为那些Python版本的标准库中内置的HTML解析方法不够稳定.
点此查看更多解析器区别

如何使用

将一段文档传入BeautifulSoup 的构造方法,就能得到一个文档的对象, 可以传入一段字符串或一个文件句柄.

from bs4 import BeautifulSoup

soup = BeautifulSoup(open("index.html"))

soup = BeautifulSoup("<html>data</html>")

首先,文档被转换成Unicode,并且HTML的实例都被转换成Unicode编码

BeautifulSoup("Sacr&eacute; bleu!")
<html><head></head><body>Sacré bleu!</body></html>

然后,Beautiful Soup选择最合适的解析器来解析这段文档,如果手动指定解析器那么Beautiful Soup会选择指定的解析器来解析文档。

四大对象

Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:
- Tag
- NavigableString
- BeautifulSoup
- Comment

Tag

概念

Tag 通俗点讲就是 HTML 中的一个个标签,例如:

<head><title>The Dormouse's story</title></head>
<a class="sister" href="http://example.com/elsie" id="link1"></a>
<p class="title" name="dromouse"><b>The Dormouse's story</b></p>

上面的 title head a p等等 HTML 标签加上里面包括的内容就是 Tag

示例

那么试着使用 Beautiful Soup 来获取 Tags:

from  bs4 import BeautifulSoup


def demo1():
    html_doc = """
    <html><head><title>The Dormouse's story</title></head>
    <body>
    <p class="title"><b>The Dormouse's story</b></p>

    <p class="story">Once upon a time there were three little sisters; and their names were
    <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
    <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
    <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
    and they lived at the bottom of a well.</p>

    <p class="story">...</p>
    """
    # 创建bs对象
    soup = BeautifulSoup(html_doc, "lxml")
    # 按照标准缩进 结构化输出html内容
    # print(soup.prettify())
    print(soup.title)
    print(soup.p)
    print(soup.a)
    print(soup.head)
    print(type(soup.body))


if __name__ == '__main__':
    demo1()

输出结果为:

<title>The Dormouse's story</title>
<p class="title"><b>The Dormouse's story</b></p>
<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
<head><title>The Dormouse's story</title></head>
<class 'bs4.element.Tag'>

我们可以利用 soup 加标签名轻松地获取这些标签的内容,这些对象的类型是bs4.element.Tag。但是注意,它查找的是在所有内容中的第一个符合要求的标签。如果要查询所有的标签,后面会进行介绍。

属性name 和 attrs
from  bs4 import BeautifulSoup


def demo1():
    html_doc = """
    <html><head><title>The Dormouse's story</title></head>
    <body>
    <p class="title"><b>The Dormouse's story</b></p>

    <p class="story">Once upon a time there were three little sisters; and their names were
    <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
    <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
    <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
    and they lived at the bottom of a well.</p>

    <p class="story">...</p>
    """
    # 创建bs对象
    soup = BeautifulSoup(html_doc, "lxml")
    # [document] #soup 对象本身比较特殊,它的 name 即为 [document]
    print(soup.name)
    # 对于其他内部标签,输出的值便为标签本身的名称
    print(soup.title.name)
    print(soup.p.name)
    print('*' * 20)
    # 把 p 标签的所有属性打印输出了出来,得到的类型是一个字典
    print(soup.p.attrs)
    # 还可以利用get方法,传入属性的名称,二者是等价的
    print(soup.p['class'])
    print(soup.p.get('class'))
    # 对属性进行修改
    soup.p['class'] = 'hello world'
    print(soup.p.attrs)
    # 删除属性
    del soup.p['class']
    print(soup.p)
    print(soup.p.attrs)

输出结果为:

[document]
title
p
********************
{'class': ['title']}
['title']
['title']
{'class': 'hello world'}
<p><b>The Dormouse's story</b></p>
{}

既然我们已经得到了标签的内容,那么问题来了,我们要想获取标签内部的文字怎么办呢?很简单,用 .string 即可,例如

    # 创建bs对象
    soup = BeautifulSoup(html_doc, "lxml")
    # 获取标签内文字
    content = soup.title.string
    print(content)
    print(type(content))

BeautifulSoup

BeautifulSoup 对象表示的是一个文档的内容。大部分时候,可以把它当作 Tag 对象,是一个特殊的 Tag,我们可以分别获取它的类型,名称,以及属性。

    soup = BeautifulSoup(html_doc, "lxml")
    print(soup.name)
    print(soup.attrs)
    print(type(soup))

输出结果为:

[document]
{}
<class 'bs4.BeautifulSoup'>

Comment

Comment 对象是一个特殊类型的 NavigableString 对象,其输出的内容不包括注释符号。

def demo1():
    html_doc = """
    <html><head><title>The Dormouse's story</title></head>
    <body>
    <p class="title"><b>The Dormouse's story</b></p>
    <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
    <p class="story">Once upon a time there were three little sisters; and their names were
    <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
    <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
    <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
    and they lived at the bottom of a well.</p>

    <p class="story">...</p>
    """
    # 创建bs对象
    soup = BeautifulSoup(html_doc, "lxml")
    print(soup.a)
    print(soup.a.name)
    print(soup.a.attrs)
    content = soup.a.string
    print(content)
    print(type(content))

输出结果为:

<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
a
{'class': ['sister'], 'href': 'http://example.com/elsie', 'id': 'link1'}
 Elsie 

遍历文档树

直接子节点
contents

tag 的 contents 属性可以将tag的子节点以列表的方式输出
输出方式为列表,我们可以用列表索引来获取它的某一个元素

def demo1():
    html_doc = """
    <html><head><title>The Dormouse's story</title></head>
    <body>
    <p class="title"><b>The Dormouse's story</b></p>
    <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
    <p class="story">Once upon a time there were three little sisters; and their names were
    <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
    <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
    <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
    and they lived at the bottom of a well.</p>

    <p class="story">...</p>
    """
    # 创建bs对象
    soup = BeautifulSoup(html_doc, "lxml")
    print(soup.head.contents)
    print(soup.body.contents)

输出结果为:

[<title>The Dormouse's story</title>]
['\n', <p class="title"><b>The Dormouse's story</b></p>, '\n', <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>, '\n', <p class="story">Once upon a time there were three little sisters; and their names were
    <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
    <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and
    <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
    and they lived at the bottom of a well.</p>, '\n', <p class="story">...</p>, '\n']
children

它返回的不是一个 list,不过我们可以通过遍历获取所有子节点。
我们打印输出 .children 看一下,可以发现它是一个 list 生成器对象。

    # 创建bs对象
    soup = BeautifulSoup(html_doc, "lxml")
    print(soup.head.children)
    for child in soup.body.children:
        print(child)

输出结果为:

<list_iterator object at 0x104e66a90>


<p class="title"><b>The Dormouse's story</b></p>


<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>


<p class="story">Once upon a time there were three little sisters; and their names were
    <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
    <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and
    <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
    and they lived at the bottom of a well.</p>


<p class="story">...</p>
所有子孙节点
descendants

.contents.children 属性仅包含tag的直接子节点,.descendants 属性可以对所有tag的子孙节点进行递归循环,和 children类似,我们也需要遍历获取其中的内容。

    # 创建bs对象
    soup = BeautifulSoup(html_doc, "lxml")
    for child in soup.descendants:
        print(child)

输出结果为:

<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>
<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
<p class="story">Once upon a time there were three little sisters; and their names were
    <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
    <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and
    <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
    and they lived at the bottom of a well.</p>
<p class="story">...</p>
</body></html>
<head><title>The Dormouse's story</title></head>
<title>The Dormouse's story</title>
The Dormouse's story


<body>
<p class="title"><b>The Dormouse's story</b></p>
<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
<p class="story">Once upon a time there were three little sisters; and their names were
    <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
    <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and
    <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
    and they lived at the bottom of a well.</p>
<p class="story">...</p>
</body>


<p class="title"><b>The Dormouse's story</b></p>
<b>The Dormouse's story</b>
The Dormouse's story


<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>
 Elsie 


<p class="story">Once upon a time there were three little sisters; and their names were
    <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
    <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and
    <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
    and they lived at the bottom of a well.</p>
Once upon a time there were three little sisters; and their names were

<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
Elsie
,

<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
Lacie
 and

<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
Tillie
;
    and they lived at the bottom of a well.


<p class="story">...</p>
...
节点内容
string

如果tag只有一个 NavigableString 类型子节点,那么这个tag可以使用 .string 得到子节点。如果一个tag仅有一个子节点,那么这个tag也可以使用 .string 方法,输出结果与当前唯一子节点的 .string 结果相同。
通俗点说就是:如果一个标签里面没有标签了,那么 .string 就会返回标签里面的内容。如果标签里面只有唯一的一个标签了,那么 .string 也会返回最里面的内容。

示例:

    # 创建bs对象
    soup = BeautifulSoup(html_doc, "lxml")
    print(soup.head.string)
    print(soup.title.string)

输出为:

The Dormouse's story
The Dormouse's story

搜索文档树

find_all(name, attrs, recursive, text, **kwargs)
  1. name参数
    name 参数可以查找所有名字为 name 的tag,字符串对象会被自动忽略掉

    A.传字符串
    最简单的过滤器是字符串.在搜索方法中传入一个字符串参数,Beautiful Soup会查找与字符串完整匹配的内容
    示例:

    
    # 创建bs对象
    
    soup = BeautifulSoup(html_doc, "lxml")
    print(soup.find_all('b'))
    print(soup.find_all('a'))

    输出结果为:

    [<b>The Dormouse's story p </b>]
    [<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>, <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>]
    

    B.传正则表达式
    如果传入正则表达式作为参数,Beautiful Soup会通过正则表达式的 match() 来匹配内容.下面例子中找出所有以b开头的标签,这表示<body><b>标签都应该被找到。
    示例:

    
    # 创建bs对象
    
    soup = BeautifulSoup(html_doc, "lxml")
    b_list = soup.find_all(re.compile('^b'))
    for tag in b_list:
        print(tag.name)

    输出结果为:

    body
    b

    C.传列表
    如果传入列表参数,Beautiful Soup会将与列表中任一元素匹配的内容返回.下面代码找到文档中所有<a>标签和<b>标签。
    示例:

    
    # 创建bs对象
    
    soup = BeautifulSoup(html_doc, "lxml")
    print(soup.find_all(['a','b']))

    输出为:

    [<b>The Dormouse's story p </b>, <a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>, <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>]
  2. keyword参数
    根据标签的id来查找,比如查找id=link3的标签。
    示例:

    soup = BeautifulSoup(html_doc, "lxml")
    print(soup.find_all(id='link3'))

    输出为:

    [<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
  3. text参数
    通过 text 参数可以搜搜文档中的字符串内容,与 name 参数的可选值一样, text 参数接受 字符串 , 正则表达式 , 列表。
    示例:

   soup = BeautifulSoup(html_doc, "lxml")
   print(soup.find_all(text='Elsie'))
   print(soup.find_all(text=re.compile('^Ti')))
   print(soup.find_all(text=['Lacie', 'Tillie']))
输出为:
['Elsie']
['Tillie']
['Lacie', 'Tillie']
CSS选择器

这就是另一种与 find_all 方法有异曲同工之妙的查找方法。
写 CSS 时,标签名不加任何修饰,类名前加.,id名前加#
在这里我们也可以利用类似的方法来筛选元素,用到的方法是 soup.select(),返回类型是 list。

通过标签名查找

示例:

    soup = BeautifulSoup(html_doc, "lxml")
    print(soup.select('title'))
    print(soup.select('a'))
    print(soup.select('p'))

输出为:

[<title>The Dormouse's story</title>]
[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>, <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>]
[<p class="title"><b>The Dormouse's story p </b></p>, <p class="story">Once upon a time there were three little sisters; and their names were
    <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
    <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a> and
    <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>;
    and they lived at the bottom of a well.</p>, <p class="story">...</p>]
通过类名查找

类名前加.
示例:

soup = BeautifulSoup(html_doc, "lxml")
print(soup.select('.sister'))

输出结果为:

[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>, <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>]
通过 id 名查找

id前需要加#
示例:

soup = BeautifulSoup(html_doc, "lxml")
    print(soup.select('#link1'))

输出结果为:

[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>, <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
组合查找

即和写 class 文件时,标签名与类名、id名进行的组合原理是一样的,例如查找 p 标签中,id 等于 link1的内容,二者需要用空格分开。

    soup = BeautifulSoup(html_doc, "lxml")
    print(soup.select('p #link1'))

输出为:

[<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]

直接子标签查找,则使用 > 分隔。
示例:

    soup = BeautifulSoup(html_doc, "lxml")
    print(soup.select('head > title'))

输出为:

[<title>The Dormouse's story</title>]
属性查找

查找时还可以加入属性元素,属性需要用中括号括起来,注意属性和标签属于同一节点,所以中间不能加空格,否则会无法匹配到。

print(soup.select('a[class="sister"]'))
#[<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>]

print(soup.select('a[href="http://example.com/elsie"]'))
#[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>]

同样,属性仍然可以与上述查找方式组合,不在同一节点的空格隔开,同一节点的不加空格

print(soup.select('p a[href="http://example.com/elsie"]'))
#[<a class="sister" href="http://example.com/elsie" id="link1"><!-- Elsie --></a>]
获取内容

以上的 select 方法返回的结果都是列表形式,可以遍历形式输出,然后用 get_text() 方法来获取它的内容。

    soup = BeautifulSoup(html_doc, "lxml")
    print(type(soup.select('title')))
    print(soup.select('title')[0].get_text())

    for title in soup.select('title'):
        print(title.get_text())

输出结果为:

<class 'list'>
The Dormouse's story
The Dormouse's story
解析有空格的class

如下,两种case,一个是class后有一个空格,第二种是class值中间含有空格,这种应该如何处理呢?

<div class="article "></div>
<div class="article block untagged mb15 typs_recent" id="qiushi_tag_120126677"></div>

在css中,class的值不应该有空格,所以第一类会忽略空格,第二类会被当做多值属性。所以在处理时也不需再考虑class值中的空格。

传入参数时用列表过滤器是最方便的,如下:

soup = BeautifulSoup(content, 'lxml')
    select_list = soup.find_all(class_=['article block untagged mb15 typs_recent','article '])

实战糗百

通过浏览器分析糗百的url和html构成,此过程略,其实就是一个寻找的过程,体力活。
废话不多说,直接上代码,注释代码中有。

from bs4 import BeautifulSoup
from urllib import request
import ssl
import json

# 存储段子列表
duanzilist = []


def demo():
    # 通过浏览器查看不同页面url变化
    url = 'https://www.qiushibaike.com/8hr/page/2/'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36'
    }
    # 忽略https校验
    context = ssl._create_unverified_context()
    req = request.Request(url, headers=headers)
    response = request.urlopen(req, context=context)
    content = response.read().decode('utf-8')
    # 转换bs对象
    soup = BeautifulSoup(content, 'lxml')
    # 通过class值获取段子列表
    content_list = soup.find_all(
        class_=['article block untagged mb15 typs_recent', 'article block untagged mb15 typs_hot',
                'article block untagged mb15 typs_old'])
    for content in content_list:
        # 将每条段子列表转换成bs对象
        div_soup = BeautifulSoup(str(content), 'lxml')
        # print(div_soup.prettify())
        # 获取昵称
        nickname = div_soup.find_all('h2')[0].get_text().strip()
        # 获取年龄
        if nickname == '匿名用户':
            age = 0
        else:
            age = div_soup.find_all(class_=['articleGender manIcon', 'articleGender womenIcon'])[0].get_text().strip()
        # 获取头像 {'alt': '『阿布』', 'src': '//pic.qiushibaike.com/system/avtnew/1417/14175454/thumb/20180327133623.JPEG?imageView2/1/w/90/h/90'}
        imageurl = div_soup.img.attrs['src']
        # 获取文本内容
        text = div_soup.select('.content')[0].get_text().strip()
        duanzi = {
            'nickname': nickname,
            'age': age,
            'imageurl': imageurl,
            'text': text
        }
        duanzilist.append(duanzi)
        print(duanzi)
    # 写入文件
    dumps = json.dumps(duanzilist, ensure_ascii=False)
    with open('duanzi.json', 'wb') as f:
        f.write(dumps.encode('utf-8'))


if __name__ == '__main__':
    demo()

输出结果为:

{'nickname': '妲妓粑割格', 'age': '27', 'imageurl': '//pic.qiushibaike.com/system/avtnew/3490/34906163/thumb/20171018211003.JPEG?imageView2/1/w/90/h/90', 'text': '你们怎么看'}
{'nickname': 'tao100', 'age': '0', 'imageurl': '//pic.qiushibaike.com/system/avtnew/3309/33099729/thumb/2016121216001450.JPEG?imageView2/1/w/90/h/90', 'text': '这是在干啥呢?蜘蛛侠被骑了!'}
{'nickname': '你好麻辣烫7', 'age': '22', 'imageurl': '//pic.qiushibaike.com/system/avtnew/3701/37016473/thumb/2018022507031116.JPEG?imageView2/1/w/90/h/90', 'text': '我是一个道士,一个洗浴中心请我去做法,说里面有鬼总在半夜上她们的技师,我在洗浴中心的大堂做了阵法,17名漂亮的女技师就在旁边窃窃私语,我给了那些女技师灵符姨妈巾,可以防鬼,做完法事后应所有女技师的邀请,我给她们传授了我的正阳之气,也就是啪啪,传授完17个人真的好累了,算了我睡觉了'}
{'nickname': '匿名用户', 'age': 0, 'imageurl': '//static.qiushibaike.com/images/thumb/anony.png?v=b61e7f5162d14b7c0d5f419cd6649c87', 'text': '够五个字吗'}
{'nickname': '唐-小龙', 'age': '29', 'imageurl': '//pic.qiushibaike.com/system/avtnew/939/9394091/thumb/20150517230854.jpg?imageView2/1/w/90/h/90', 'text': '公司一员工,刚才让他去物流公司取货,他回来了!物流公司给我打电话了!你们取货的是个啥子人?把单子给我拿走了,钱也不给,货也不拿,就走了!就走了,他真的把货运单子拿回来了[大哭][大哭]'}
{'nickname': '花七七…', 'age': '28', 'imageurl': '//pic.qiushibaike.com/system/avtnew/3410/34105982/thumb/201712301452405.JPEG?imageView2/1/w/90/h/90', 'text': '忘记带钥匙,打电话叫开锁,那师傳跟我说上门要五十块,心痛自己的零花钱,然后助跑,跳起来凌空一脚,门开了。不得不说修门比开锁贵得多了。'}
{'nickname': '羊羊羊羊咩咩咩', 'age': '25', 'imageurl': '//pic.qiushibaike.com/system/avtnew/2681/26815788/thumb/20170618223455.JPEG?imageView2/1/w/90/h/90', 'text': '旺夫相,,,'}
{'nickname': '沃土秋实', 'age': '54', 'imageurl': '//pic.qiushibaike.com/system/avtnew/3221/32214346/thumb/20180124025918.JPEG?imageView2/1/w/90/h/90', 'text': '一男子连续相亲三十六次,仍没找到中意的。红娘说:自已从上世纪八十年代初就帮他介召寻摸。那年他才二十九岁,直到现在也没找到合适的,今年他六十五了,。。。。。。。。即便如此,男子也始终不肯降低择偶标准。有人问他是否降标准,男子说,宁可把那个耗尽了,也是铁板一块。'}
{'nickname': '非法用户名f9xs…', 'age': '36', 'imageurl': '//pic.qiushibaike.com/system/avtnew/2620/26207460/thumb/20150324232438.jpg?imageView2/1/w/90/h/90', 'text': '春天来了,它也有心事了!'}
{'nickname': '星劫', 'age': '27', 'imageurl': '//pic.qiushibaike.com/system/avtnew/1484/14849114/thumb/nopic.jpg?imageView2/1/w/90/h/90', 'text': '儿子在农村我妈那里住了两天,吃了邻居一顿大锅菜吃上瘾了,天天往人家家里跑,深怕人家不给他吃,学电视里嚷嚷着和邻居拜把子,关键是邻居都已经四十多岁了,后来让我爸知道了,把我儿子一顿好打,按辈分,我爸都管人家叫爷……'}
{'nickname': '楼主他大娘', 'age': '31', 'imageurl': '//pic.qiushibaike.com/system/avtnew/3317/33173941/thumb/20171026084304.JPEG?imageView2/1/w/90/h/90', 'text': '和老公聊起家暴,我说“如果你敢对我家暴,我半夜起来捅死你”老公一脸鄙视的看着我,我“你是认为我不敢捅你””?”老公“我TM认识你这么多年,你啥时候半夜醒过”'}
{'nickname': '我觉得不会有人看', 'age': '27', 'imageurl': '//pic.qiushibaike.com/system/avtnew/3234/32347165/thumb/2016122109574051.JPEG?imageView2/1/w/90/h/90', 'text': '今天刚碰到的!是他们太傻还是我太聪明了!'}
{'nickname': '十里柔情一帘幽梦', 'age': '100', 'imageurl': '//pic.qiushibaike.com/system/avtnew/873/8737794/thumb/2018031808432962.JPEG?imageView2/1/w/90/h/90', 'text': '老公喜欢在我身上种草莓,一次穿低领衣服,脖子上的印被我老妈看到了,我不好意思地解释到:不小心磕到了。一会儿听到我妈对我姐说:你妹妹是不是傻,脖子磕这样不得进医院,还不如说是蚊子咬的呢!'}
{'nickname': '匿名用户', 'age': 0, 'imageurl': '//static.qiushibaike.com/images/thumb/anony.png?v=b61e7f5162d14b7c0d5f419cd6649c87', 'text': '苦逼的安装工。。发发牢骚。大神们。手下留情啊。。。。'}
{'nickname': '风吹屁股蛋子疼', 'age': '35', 'imageurl': '//pic.qiushibaike.com/system/avtnew/3691/36912791/thumb/20180322224251.JPEG?imageView2/1/w/90/h/90', 'text': '去学校接儿子放学,儿子对着同学说,我爸爸有一辆摩托车,还有一辆电动车!一脸的自豪!我听了赶紧拉孩子走,儿子,爸爸脸都红了,别人都是开小轿车来接孩子,爸爸骑个电动车就不要显摆了……'}
{'nickname': '逆风的单车^O^', 'age': '30', 'imageurl': '//pic.qiushibaike.com/system/avtnew/3059/30591370/thumb/20171217185111.JPEG?imageView2/1/w/90/h/90', 'text': '挤公交,坐我旁边一大哥,一脸认真的玩连连看,我忍不住多看几眼,大哥突然就卡住了,然后对我说“兄弟,你能不能别看了,让你看的我都不会了!”。。。。'}
{'nickname': '老沙他哥', 'age': '47', 'imageurl': '//pic.qiushibaike.com/system/avtnew/2727/27275208/thumb/20170702172616.JPEG?imageView2/1/w/90/h/90', 'text': '我。。。。。。。这真皮'}
{'nickname': '种橙子的C先生', 'age': '32', 'imageurl': '//pic.qiushibaike.com/system/avtnew/3177/31771524/thumb/20171214172621.JPEG?imageView2/1/w/90/h/90', 'text': '梦到自己跟人签了个200万的对赌协议,然后把自己吓醒了,尼玛,果然是人穷志气短。'}
{'nickname': '杨帆~起航', 'age': '26', 'imageurl': '//pic.qiushibaike.com/system/avtnew/1983/19838875/thumb/20150121204454.jpg?imageView2/1/w/90/h/90', 'text': '回味经典,还有没有在用的!'}
{'nickname': '匿名用户', 'age': 0, 'imageurl': '//static.qiushibaike.com/images/thumb/anony.png?v=b61e7f5162d14b7c0d5f419cd6649c87', 'text': '女儿咳嗽我不给她吃零食,她就求她奶奶。奶奶说,不可以哦,你看你妈妈在瞪我,要是我给你吃,我老了你妈肯定不给饭我吃!我女儿小声的说,奶奶你放心,你给我吃一颗糖,等我长大了,赚的钱都给你买饭吃,不给坏蛋妈妈……好吧,恶人永远是我!'}
{'nickname': '傻月.', 'age': '30', 'imageurl': '//pic.qiushibaike.com/system/avtnew/2722/27226098/thumb/20180319072345.JPEG?imageView2/1/w/90/h/90', 'text': '闺蜜老公承包了一个快递站,刚才闺蜜打电话给我哭诉,说给收件人打电话着,然后自己就骨折了。赶忙去看她,我:“怎么打电话还能骨折啊”闺蜜:“给收件人打电话,说那个快件是刷单的,让我直接签收就行了。”我:“那跟你骨折有什么关系?”闺蜜:“那个快件是个小纸箱,好奇拆开看了,掉出来半块砖头,拍我脚上了!”我:“……”'}
{'nickname': '流盲人', 'age': '30', 'imageurl': '//pic.qiushibaike.com/system/avtnew/2324/23248545/thumb/20141203175851.jpg?imageView2/1/w/90/h/90', 'text': '单身太久了,习惯了一个人生活都不知道怎么追女孩子有没有那种不用追的来聊聊。'}
{'nickname': '姑苏云琪', 'age': '25', 'imageurl': '//pic.qiushibaike.com/system/avtnew/3707/37076223/thumb/20180228125455.JPEG?imageView2/1/w/90/h/90', 'text': '上班无聊的时候手机在线看起了爱情动作片。老板从后面拍拍我的肩膀,然后丢给我一个优盘说:呢,我这有更好的!跟着里面的好好学学!刚刚老板说下周让我跟他一起出差,我好像明白了老板那句“好好学学”的意思。'}
{'nickname': '匿名用户', 'age': 0, 'imageurl': '//static.qiushibaike.com/images/thumb/anony.png?v=b61e7f5162d14b7c0d5f419cd6649c87', 'text': 'lz男,年底喜的一子,不隔,以后要用,现四十来天,这坑爹货今天我我给他换纸尿裤的时候喷我一脸屎,,,'}

并且,在代码中,将抓取到的数据写入文件(其实应该存库),可以查看一下结果。

好了,BeautifulSoup的简单介绍和案例就介绍到这了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值