Python爬虫初级(四)—— 信息组织与提取方法

信息标记的三种形式

信息的标记:
标记后的信息可形成信息组织结构,增加信息维度
标记后的信息可用于通信、存储或展示
标记的结构和信息一样具有重要价值
标记后的信息更利于程序理解和运用

国际公认的信息标记的三种形式分别是 XML、JSON、YAML,下面分别介绍这三者:
XML 即 eXtensible Markup Language,采用了以标签为主来构建信息和表达信息的方式,比如:

1
2
3
<img src="china.jpg size="10"> ... </img>
<img src="china.jpg size="10" />
<!-- This is a comment -->

我们不难发现,XML 的形式与 HTML 几乎完全一致,可以说 XML 是通过 HTML发展而来的通用表达形式。
另一种信息标记形式是 JSON (JavaScript Object Notation),它是 JavaScript 语言中对面向对象的信息的一种表达形式,简单来讲,JSON 是由有类型的键值对构建的信息表达方式,具体形式如下:

1
2
3
"key1":"value1"
"key2":["value2", "value3"]
"key3":{"subkey":"subvalue"}

YAML(YAML Ain’t Markup Language) 是一种递归的定义,采用的是五类型的键值对来组织信息,和 Python 语言类似,YAML 通过缩进的方式表达所属关系比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
name:	# 用 tab 表示所属关系
newName : abc
oldName : ABC

name: # 用-表示并列关系
-abc
-ABC

text: | # 用 | 表示整块数据
简介:汉武帝刘彻(前156年7月7日—前87年3月29日),
西汉第七位皇帝(含前后少帝),政治家、文学家。
汉武帝在位期间(前141年—前87年),在政治上,创设中外朝制、刺史制、察举制,
颁行推恩令,加强君主专制与中央集权。

三种信息标记形式的比较

信息标记形式 特点 应用情况
XML 是最早的通用信息标记语言,可扩展性好,但较为繁琐 Internet 上的信息交互与传递
JSON 信息有类型,适合程序处理,比 XML 更简洁 移动应用云端和节点的信息通信,无注释
YAML 信息无类型,文本信息比例最高,可读性好 各类系统的配置文件,有注释易读,应用相对较广泛

信息提取的一般方法

方法 例子 优点 缺点
完整解析信息标记形式,再提取关键信息,需要标记解析器 bs4 库的标签树遍历 信息解析准确 提取过程繁琐、速度慢
无视标记形式,直接搜索关键信息 Word 对信息的文本查找函数 提取过程简介,速度较快 提取结果准确性与信息内容相关

实际上更常用的是两者结合的融合方法:即结合形式解析与搜索方法,提取关键信息,这需要标记解析器及文本查找函数。下面我们考虑实例:提取 HTML 中所有的 URL 链接,具体思路是:

1) 搜索所有 \ 标签
2) 解析 \
标签格式,提取 href 后的链接内容

具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> import requests
>>> from bs4 import BeautifulSoup
>>> url = "http://python123.io/ws/demo.html"
>>> res = requests.get(url)
>>> demo = res.text
>>> demo
'<html><head><title>This is a python demo page</title></head>\r\n<body>\r\n<p class="title"><b>The demo python introduces several python courses.</b></p>\r\n<p class="course">Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:\r\n<a href="http://www.icourse163.org/course/BIT-268001" class="py1" id="link1">Basic Python</a> and <a href="http://www.icourse163.org/course/BIT-1001870001" class="py2" id="link2">Advanced Python</a>.</p>\r\n</body></html>'
>>> soup = BeautifulSoup(demo, "html.parser")
>>> for link in soup.find_all("a"):
print(link.get("href"))

http://www.icourse163.org/course/BIT-268001
http://www.icourse163.org/course/BIT-1001870001

基于 BeautifulSoup 库的内容查找方法

由前例我们可以看见, find_all 方法可以返回一个列表类型,存储查找的结果,find_all 的具体使用方法为:

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

其中,name 为对标签的检索字符串,如果我们希望查找两个标签,可以以列表形式传入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

>>> soup.find_all("a")
[<a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a>, <a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced Python</a>]
>>> soup.find_all(["a","b"])
[<b>The demo python introduces several python courses.</b>, <a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a>, <a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced Python</a>]

>>> for tag in soup.find_all(true):
print(tag.name)

html
head
title
body
p
b
p
a
a

我们看到,若 find_all(true) ,则会返回所有标签。若希望只显示所有以 b 开头的标签,包括 b 和 body 标签,我们应该怎么办呢?这时我们应该使用正则表达式:

1
2
3
4
5
6
>>> import re
>>> for tag in soup.find_all(re.compile('b')):
print(tag.name)

body
b

find_all 的第二个参数 attrs 是对标签属性值的检索字符串,可标注属性检索。

1
2
3
4
5
6
7
8
9
10
>>> soup.find_all("p", "course")
[<p class="course">Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:
<a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a> and <a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced Python</a>.</p>]

>>> soup.find_all(id="link1")
[<a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a>]
>>> soup.find_all(id="link")
[]
>>> soup.find_all(id=re.compile("link"))
[<a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a>, <a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced Python</a>]

find_all 的第三个参数是 recursive,即是否对子孙进行全部检索,默认为 True。

1
2
3
4
>>> soup.find_all("a")
[<a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a>, <a class="py2" href="http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced Python</a>]
>>> soup.find_all("a",recursive=False)
[]

上述代码说明,soup 的根节点下是没有 a 标签的, a 标签在其子孙节点中。
find_all 的第四个参数是 string,是对 <>... 中字符串区域的检索字符串,下面看一个例子:

1
2
3
4
5
6
7
>>> import re 
>>> soup.find_all(string="Basic Python")
['Basic Python']
>>> soup.find_all(string="Python")
[]
>>> soup.find_all(string=re.compile("Python"))
['Python is a wonderful general-purpose programming language. You can learn Python from novice to professional by tracking the following courses:\r\n', 'Basic Python', 'Advanced Python']

事实上,我们有一个简写的形式,即:

\(…) 等价于 \.find_all(…)
soup(…) 等价于 soup.find_all(…)

BeautifulSoup 库有八个常用方法,都是顾名思义的,就不在此做详细介绍了,方法列举为:find_all, find, find_parent, find_parents, find_next_siblings, find_next_sibling, find_previous_sibling, find_previous_siblings

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2020 chenk
  • 由 帅气的CK本尊 强力驱动
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信