一、信息标记的三种形式
我们需要对信息进行表记,使得我们能够理解信息所反馈的真实含义。
标记后的信息可形成信息组织结构,增加了信息维度
标记的结构与信息一样具有重要价值
标记后的信息可用于通信、存储或展示
标记后的信息更利于程序理解和运用,也利于人对信息的深入理解与运用
HTML的信息标记
HTML是WWW(World Wide Web)的信息组织方式
它能够将声音、图像、视频等超文本信息嵌入到文本中
HTML通过预定义的<>…</>标签形式组织不同类型的信息
现在国际公认的信息标记格式有三种,分别是XML,JSON和YAML
XML(eXtensible Markup Language)叫做扩展标记语言,它是一种与HTML很接近的标记语言。它以标签(Tag)为主来标记信息
<img src=“china.jpg” size=“10”> … </img>
它有名称 Name和属性Attribute
如果标签中没有内容,我们可以用相关的缩写形式,用一个尖括号来表示一个标签。
<img src=“china.jpg” size=“10” />空元素的缩写形式
在XML中也可以嵌入注释,它以<!开头,并且以>结尾
<!‐‐ This is a comment, very useful ‐‐>注释书写形式
可以说XML是HTML发展以来的一种通用的信息标记格式
JSON(JavsScript Object Notation),它是JavaScript语言中面向对象的一种语言形式,简单讲JSON是一种有类型的键值对构建的信息表达方式。键值对是key:value的一个组合,也就是给出一个信息,并且对信息内容做一个定义。其中对信息类型的定义叫“键”,对信息值的描述叫value。
要注意,无论是键还是值,它都通过增加双引号来表示它是字符串。说明它是一个有数据类型的键值对。
如果一个键对应多个值的时候,我们使用方括号加逗号[,]的形式来组织
键值对可以嵌套使用,也就是一个键值对放在另一个键值对的值的部分,在嵌套使用时,我们用大括号来表示
总结:JSON用有类型的键值把信息组织起来
“key” : “value”
“key” : [“value1”, “value2”]
“key” : {“subkey” : “subvalue”}
JSON语言使用有类型的键值对,一个很大好处就是对于JavaScript等编程语言来说可以直接将JSON格式变为程序的一部分,使得编写程序大大地简化
YAML(YAML Ain’t Markup Language),它在命名的时候使用一种递归的定义。它也使用键值对,不过是无类型键值对key:value。可以用缩进来表达所属的关系,用减号表达并列关系,用竖线表达整块数据,用#表示注释
key : value
key : #Comment
‐value1
‐value2
key :
subkey : subvalue
三种信息标记形式的比较
XML实例:
<person>
<firstName>Tian</firstName>
<lastName>Song</lastName>
<address>
<streetAddr>中关村南大街5号</streetAddr>
<city>北京市</city>
<zipcode>100081</zipcode>
</address>
<prof>Computer System</prof><prof>Security</prof>
</person>
每一个信息域定义相关的标签,并且用嵌套的形式组织起来
在整个文本中,有效信息所占的比例并不高,大多数信息被标签占用
JSON实例:
{
“firstName” :“Tian” ,
“lastName” :“Song” ,
“address” : {
“streetAddr” :“中关村南大街5号” ,
“city” :“北京市” ,
“zipcode” :“100081”
} ,
“prof” : [ “Computer System” ,“Security” ]
}
JSON使用键值对的形式组织信息,但是无论标签还是后面的值,键值都要用双引号来表达它们的类型
YAML实例:
firstName : Tian
lastName : Song
address :
streetAddr : 中关村南大街5号
city : 北京市
zipcode : 100081
prof :
‐Computer System
‐Security
用无类型的键值对来表示,很简洁的关联
XML:最早的通用信息标记语言,可扩展性好,但繁琐
JSON:信息有类型,适合程序处理(js),较XML简洁
YAML:信息无类型,文本信息比例最高,可读性好
实际使用中:
XML:Internet上的信息交互与传递
JSON:移动应用云端和节点的信息通信,无注释
YAML:各类系统的配置文件,有注释易读
二、信息提取的一般方式
信息提取指,从标记后的信息中提取所关注的内容。之前的XML,JSON,YAML的三种形式,无论哪种形式,在信息提取中,包含标记,和信息两部分,我们关心的是所要提取出的内容
·方法一:完整解析信息的标记形式,再提取关键信息
用标记解析器去解析XML JSON YAML格式,然后将其中所需要的信息提取出来
例如:bs4库的标签树遍历
优点:信息解析准确
缺点:提取过程繁琐,速度慢
·方法二:无视标记形式,直接搜索关键信息
对信息的文本查找函数即可
优点:提取过程简洁,速度较快
缺点:提取结果准确性与信息内容相关
·融合方法:结合形式解析与搜索方法,提取关键信息
XML JSON YAML 搜索
需要标记解析器及文本查找函数
实例:
提取HTML中所有URL链接
思路: 1) 搜索到所有<a>标签
2) 解析<a>标签格式,提取href后的链接内容
import requests
r = requests.get("http://python123.io/ws/demo.html")
demo = r.text
from bs4 import BeautifulSoup
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
三、基于bs4库的HTML内容查找方法
import requests
r = requests.get(“http://python123.io/ws/demo.html”)
demo = r.text
<>.find_all(name, attrs, recursive, string, **kwargs)
find_all方法可以在soup的变量中查找里面的信息
它能够返回一个列表类型,存储查找的结果
第一个参数name:对标签名称的检索字符串
from bs4 import BeautifulSoup
soup = BeautifulSoup(demo,"html.parser")
print(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>]
如果想要同时得到a和b,则用一个方括号
print(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>]
如果给出的标签名称是True,则显示当前标签的所有信息
for tag in soup.find_all(True):
print(tag.name)
html
head
title
body
p
b
p
a
a
我们看到这个文档中的所有标签名称被打印了出来
希望只显示其中以b开头的标签,包括b和body标签,就需要使用一个新的第三方库,叫做“正则表达式库”
首先引入这个库
正则表达式反馈的结果是以b开头的所有表达的信息
import re
for tag in soup.find_all(re.compile('b')):
print(tag.name)
body
b
attrs: 对标签属性值的检索字符串,可标注属性检索
我们查找p标签中中包含course字符串的信息
print(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>]
我们也可以对属性值作约定
print(soup.find_all(id='link1'))
[<a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a>]
print(soup.find_all(id='link'))
[]
所以我们对属性赋值要做精确的赋值
如果我们需要查找包含link的属性,我们就需要引入正则表达式库
print(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>]
正则表达式就像平常搜索一样搜索词的一部分,如果不使用正则表达式就需要完整准确地给出词的信息,不多也不少
recursive: 是否对子孙全部检索,默认True
如果我们只需要搜索儿子这一层面的信息,我们就把recursive设为False
print(soup.find_all('a',recursive=False))
[]
string: <>…</>中字符串区域的检索字符串
print(soup.find_all(string='Basic Python'))
['Basic Python']
print(soup.find_all(string=re.compile('python')))
['This is a python demo page', 'The demo python introduces several python courses.']
<tag>(..) 等价于 <tag>.find_all(..)
soup(..) 等价于 soup.find_all(..)
拓展方法
方法 | 说明 |
<>.find() | 搜索且只返回一个结果,同.find_all()参数 |
<>.find_parents() | 在先辈节点中搜索,返回列表类型,同.find_all()参数 |
<>.find_parent() | 在先辈节点中返回一个结果,同.find()参数 |
<>.find_next_siblings() | 在后续平行节点中搜索,返回列表类型,同.find_all()参数 |
<>.find_next_sibling() | 在后续平行节点中返回一个结果,同.find()参数 |
<>.find_previous_siblings() | 在前序平行节点中搜索,返回列表类型,同.find_all()参数 |
<>.find_previous_sibling() | 在前序平行节点中返回一个结果,同.find()参数 |
区别仅在于查找区域的不同以及检索返回的结果个数不同