1,前言
我们已经明白了如何处理HTML文本,想一想,一锅粥,print,就会有神奇的出现。但是在标签中或者说网页里的一些信息我们应该怎么提取呢,看到文章的标题,或许你已经猜到了,那我们就看一看是不是和大家的猜想一样?
2,信息标记的三种形式
2.1,什么是信息标记
如果是一组信息,你阔能会很快看出来是什么意思,
如果是一组信息呢?
小明、2001、软件工程、北京。
看上去是再说一个事,但是就很难理解。因此我们就要用到信息标记,整理一下:
姓名:小明
出生年份:2001
所学专业:软件工程
居住地:北京
这样看是不是就清晰了。
- 标记后的信息可形成信息组织结构,增加了信息维度。
- 标记后的信息可用于通信、存储、或展示
- 标记的结构与信息一样具有重要价值
- 标记后的信息更利于程序的理解和运用
以上就是他的相关概念,不难理解,通过上面演示也可以看出很重要吧
2.2,HTML的信息标记
- HTML:(hyper text Markup language)超文本标记语言
- HTML是www(World Wide Web)的信息组织方式
- 可以将声音、图像、音频等超文本的信息嵌入到文本当中
- HTML通过预定义的
<>...</>
的标签形式组织不同类型的信息
这四点似曾相识。之前也大概描述过。就是再说网页,网页有图片、音频、声音等等等。
2.3,信息标记种类、
说了那么多,都是铺垫。仿佛并不是我们想要知道的
目前,世上公认的信息标记种类有三种形式:XML、JSON和YAML、几人看到这了,让我们分别了解一下。
2.3.1,XML
-
XML:(eXtensible Markup Language)可扩展标记语言
-
空格元素的缩写形式
<img src="china.jpg" size="10" /> 复制代码
-
注释书写形式‘
<!--This is a comment, very useful --> 复制代码
-
xml通过标签形式来构建所有信息,有三种经常使用的方式
<name>...</name>
:标签中有内容<name />
:标签中没有内容<!-- -->
:注释
与html接近,也有标签tag、名字name、属性attribute。
看上去是不是和HTML相似,你有的我也有。
其实在历史发展中先有了HTML格式,再有了xml格式。因此可以说xml格式是基于HTML格式发展以来的一种通用的信息表达形式
3.3.2, JSON
-
JSON:(JavaScript Object Notation)
-
有类型的键值对:key: value
信息类型的定义是key;信息值得描述value。
-
用法
"姓名": "小明" "出生年份": 2001 复制代码
**注:**增加“”表示他是字符串类型,如果是数字,请忽略。
当一个键有多个值的时候
"name": ["小明", "小刚"] 复制代码
也可以嵌套使用:
"小明": { "性别":“男”, “专业”: "软件工程" } 复制代码
键值对嵌套采用
{,}
形式。 -
他的所有格式总结如下:
"key" : "vaule"
:"key" : ["vaule1", "vaule2"]
:一个键有多个值"key" : {"subkey": "subvalue"}
:嵌套形式
3.3.3,YAML
-
YAML:YAML Ain’t a Markup Language
无类型键值对
key:value
-
使用方法
姓名 : 小明 复制代码
我们以JSON相比会发现yaml仅字符串,没有双引号。
我们也可以通过缩进的方式表达所属关系
小明 : 性别 : 男 专业 : 软件工程 复制代码
用
-
表达并列关系软件工程 : - 小明 - 小红 复制代码
|
表示整块数据,#
:表示注释yaml: | # 一段yaml介绍YAML(/ˈjæməl/,尾音类似camel骆驼)是一个可读性高,用来表达数据序列化的格式。YAML参考了其他多种语言,包括:C语言、Python、Perl,并从XML、电子邮件的数据格式(RFC 2822)中获得灵感。Clark Evans在2001年首次发表了这种语言,另外Ingy döt Net与Oren Ben-Kiki也是这语言的共同设计者。当前已经有数种编程语言或脚本语言支持(或者说解析)这种语言。 复制代码
-
所有使用方式
key : vaulekey : #Comment- value1- value2key : subkey : subv 复制代码
3, 三种信息标记形式的比较
3.1,回顾
我们先回顾一下三种不同信息标记形式
-
XML
<name>...</name><name /><!-- --> 复制代码
用
<>
和标签表达信息 -
JSON
"key" : "vaule:"key" : ["vaule1", "vaule2"]"key" : {"subkey": "subvalue"} 复制代码
用有类型的键值对表达信息
-
YAML
key : vaulekey : #Comment- value1- value2key : subkey : subv 复制代码
用无类型键值对表达信息
3.2,实例
我们再分别看一下他们的实例
-
XML
<person> <fistName>Tian</fistName> <lastName>Song</lastName> <address> <streeAddr>中关村南大街5号</streeAddr> <city>北京市</city> <zipcode>100081</zipcode> </address> <prof>Computer System</prof><prof>Security</prof></person> 复制代码
关键信息用标签组织起来,一眼望去大部分都是标签,有效信息就那么几个。
-
JSON
{ "fistName" : "Tian" , "lastName" : "Song" , "address" :{ "streeAddr" : "中关村南大街5号" , "city" : "北京市" , "zipcode" : "100081" } , "prof" : [ "Computer System" , "Security"]} 复制代码
可以看出有类型的字符串,必须有双引号
-
YAML
fistName : TianlastName : Songaddress : streeAddr : 中关村南大街5号 city : 北京市 zipcode : 100081prpf :- Computer System- Security 复制代码
看上去比前两个都简洁
3.3,三种信息标记i形式的比较
-
XML:最早的通用信息标记语言,扩展性好,但繁琐。常用于inter上的信息交互与传递。
-
json:信息有类型,适合程序处理(js),比XML简洁。常用于移动应用云端和节点的信息通信,无注释。
-
YAML:信息无类型,文本信息比例最高,可读性好。常用于各类系统的配置文件,有注释易读。
没有对比就没有伤害,这三种形式,要我选择我肯定喜欢YAML,洁简,看起来很舒服,当我们不能否认其他两种没有任何用,json经常用于程序接口,需要不知道什么是接口,XML在互联网上也很吃香,但是对于我这种学习者也是YAML确实不错。
4,信息提取的一般方式
说过了信息标记,那么标记后的信息如何提取出来呢?
信息提取,是指从所标记的信息中提取内容,无论哪种形式,都有两部分组成标记和信息,我们关心的是我们所要提出的信息内容,
有三种方法,我们看看
-
方法一:完整解析信息的标记形式,再提取关键信息
XML,JSON,YAML需要标记解析器,例如:bs4库的标签树遍历
优点:信息解析准确
缺点:提取信息过程繁琐,速度慢
虽然没有试过,但是看到bs4库的遍历,想到了HTML,他们的工作原理应该和HTML很相像,需要记住整个文件的信息组织,做到认识和了解。
-
方法二:无视标记形式,直接搜索关键信息。
搜索,对信息的文本查找函数即可
优点:提取过程简单,速度较快,
缺点:提取信息结果准确性与内容无关
这个类似word里面的Ctrl+F,速度确实快,但是准确性不好说。
-
融合方法
结合解析形式与搜索方法,,提取关键信息。
XML,JSON,YAML。搜索
需要标记解析器及文本查找函数。
4.1,实例
我们提取HTML页面中所url链接
思路,通过分析网页,可以看到a标签里有ur链接,
再找到head属性
我们做出代码
>>> 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-268001http://www.icourse163.org/course/BIT-1001870001
复制代码
会发现有两个新面孔,.find_all()
和.get()
表示问题保留,看下面。
5,基于bs4库的HTML内容查找方法
4.1,回顾
想必这个图片大家已经不再陌生了吧?
4.2,<>.find_all()
方法
之前,我们遇到了一个方法,<>.find_all()
,我们现在了解一下
这个方法可以在soup变量中查找信息。里面的信息
find:查找的意思。
<>.fild_all(name, attrs, resursive, string, **kwargs)
复制代码
一共有五个参数,了解一下。
返回一个列表类型,存储查找的结果。
-
name:对标签名称的检索字符串。
我们试试检索p标签
>>> soup.find_all("p")[<p class="title"><b>The demo python introduces several python courses.</b></p>, <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="https://juejin.cn/post/http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced Python</a>.</p>] 复制代码
可以看到返回了一个列表,里面有结果。
我还想看看b标签
>>> soup.find_all(["p","b"])[<p class="title"><b>The demo python introduces several python courses.</b></p>, <b>The demo python introduces several python courses.</b>, <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="https://juejin.cn/post/http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced Python</a>.</p>]>>> 复制代码
如果给出的标签是True,返回soup所有标签
>>> for tag in soup.find_all(True): print(tag.name)htmlheadtitlebodypbpaa 复制代码
如果说返回以b开头的标签呢?
这里我们就需要用到正则表达式库了,我们一起来看看
import re>>> for tag in soup.find_all(re.compile("b")): print(tag.name)bodyb 复制代码
标签需要以b开头。
-
attrs:对标签属性值的检索字符串,可标注属性检索。检索某一个标签中是否包含了某些字符信息。
查看p标签有没有包含course信息
>>> 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="https://juejin.cn/post/http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced Python</a>.</p>] 复制代码
返回了p标签属性有course的信息。
当然也阔以对属性值做一些约定,比如查找id=”link1″作为查找元素。
>>> soup.find_all(id="link1")[<a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a>] 复制代码
可以看出,打印出来了。
如果是link呢?
>>> 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="https://juejin.cn/post/http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced Python</a>] 复制代码
看似很简单。
-
recursive:是否是子孙全部检索,默认为true。
什么意思呢,我们搜索的是从当前标签开始的以下信息,如果想搜索当前节点儿子的信息,设为false。
我们先查找a标签下的信息
soup.find_all("a")[<a class="py1" href="http://www.icourse163.org/course/BIT-268001" id="link1">Basic Python</a>, <a class="py2" href="https://juejin.cn/post/http://www.icourse163.org/course/BIT-1001870001" id="link2">Advanced Python</a>] 复制代码
我们在查找一下a标签的儿子标签节点
>>> soup.find_all("a",recursive=False)[] 复制代码
可以看见为空。直接说他没有儿子。
-
string:
<>...</>
中字符串区域的检索字符串。我们去检索一下字符串 Basic python,
>>> soup.find_all(string = "Basic Python")['Basic Python'] 复制代码
还是需要我们精准输入,如果输入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'] 复制代码
此时就会打印与python字符串有关的字符串
由于<>.find_all()
方法非常常用,因此他还有属于他的简写形式
<tag>(...)
等价于<tag>.find_all(...)
soup(…)等价于
soup.find_all(…)`
<>.find_all()`方法还有七个扩展方法
方法 | 说明 |
---|---|
find() |
搜索且只返回一个结果,字符串类型,同find_all() 参数。 |
<>.find_parents() |
在先辈节点中搜索,返回列表类型,同find_all() 参数。 |
<>.find_parent() |
在先辈节点中返回一个结果,字符串类型,同find_all() 参数。 |
<>.find_next_siblings() |
在后序平行节点中搜索,返回类别类型,同find_all() 参数。 |
<>.find_next_sibling() |
在后序平行节点中返回一个结果,返回类别类型,同find_all() 参数。 |
<>.find_previous_siblings() |
在前序平行节点中搜索,返回类别类型,同find_all() 参数。 |
<>.find_previous_sibling() |
在前序平行节点中返回一个结果,返回类别类型,同find_all() 参数。 |
通过之前的所学与一些字眼,我们大概了解,他们只是搜索范围与返回结果不同,而且这6+1个方法也是非常好记,
6,总结
可以说是提取网页内容,但是不是和我想象的不太一样。现在我似乎理解了。是通过HTML文本中使用find_all
方法。然后得到我们想要的内容,
这里应该也是对正则表达式有了个认识,就是用来做搜索用的。
这就是以上内容,我的笔记。
谢谢您的,如果文章有错误,欢迎你的指正;如果对您有帮助,是我的荣幸。