(三)BeautifulSoup

一、BeautifulSoup_demo

>>> from urllib.request import urlopen
>>> from bs4 import BeautifulSoup
>>> html = urlopen("http://www.pythonscraping.com/pages/page1.html")
>>> bs0bj = BeautifulSoup(html.read(),'lxml') 
# 加不加 .read() 好像没差,但一次请求只能 read 一次
>>> bs0bj
<html>
<head>
<title>A Useful Page</title>
</head>
<body>
<h1>An Interesting Title</h1>
<div>
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</div>
</body>
</html>

#HTML节点附近的信息都可以提取
#获取bs0bj里面的title标签里的内容
>>> print(bs0bj.title)
<title>A Useful Page</title>
>>> print(bs0bj.html.body.h1)
<h1>An Interesting Title</h1>
>>> print(bs0bj.div) 
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

#可以用节点不同的方法调用到同一标签
>>> print(bs0bj.html.body.h1)
<h1>An Interesting Title</h1>
>>> print(bs0bj.body.h1)
<h1>An Interesting Title</h1>
>>> print(bs0bj.html.h1)
<h1>An Interesting Title</h1>

#get_text()去除标签获取纯文本内容
>>> print(bs0bj.html.body.h1.get_text())
An Interesting Title

解析器

解析器 使用方法 优劣势
Python标准库 BeautifulSoup(markup, "html.parser") 速度适中,内置标准库
lxml HTML 解析器 BeautifulSoup(markup, "lxml") , BeautifulSoup(markup, "xml") 速度快,推荐这个
lxml XML 解析器 BeautifulSoup(markup, ["lxml", "xml"]) 速度快
html5lib BeautifulSoup(markup, "html5lib") 生成HTML5格式的文档

二、基本元素

  • Tag 标签
  • Name 标签名
  • Attributes 属性
  • NavigableString .string
  • Comment 注释

三、遍历功能

(一)下行遍历

.contents
.children
.descendants

(二)上行遍历

.parent
.parents

(三)平行遍历

.next_sibling
.previous_sibling
.next_siblings
.previous_siblings

(四)find_all()

find_all(name, attrs, recursive, text, **kwargs)

find_all方法搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件.这里有几个例子(返回的是列表):

soup.find_all("title")

[<title>The Dormouse's story</title>]

soup.find_all("p", "title")

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

soup.find_all("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>]

soup.find_all(id="link2")

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

import re
soup.find(text=re.compile("sisters"))

u'Once upon a time there were three little sisters; and their names were\n'

1、name参数 (name)

name参数可以查找所有名字为 name 的 tag,字符串对象会被自动忽略掉

soup.find_all("title")
[<title>The Dormouse's story</title>]

2、keyword参数 (attr, **kwargs)

搜索 tag 标签内指定属性的参数 ,如 id='link2', href='href=re.compile("elsie")。class属性要用 class_ ,因为 class 是类的关键字,见按 css 搜索。

soup.find_all(id='link2')
[<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
soup.find_all(href=re.compile("elsie"))
[<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]

参数值可以为字符串,正则表达式,列表,True
下面的例子在文档树中查找所有包含 id 属性的tag,无论 id 的值是什么:

soup.find_all(id=True)
[<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.find_all("a", {"class":"sister"})

a->标签,{}->标签的属性和其对应值

images = bs0bj.find_all("img", {"src":re.compile(".?")})
找出img标签里src属性里的所有东西re.compile(".
?")匹配所有

使用多个指定名字的参数可以同时过滤tag的多个属性:

soup.find_all(href=re.compile("elsie"), id='link1')
[<a class="sister" href="http://example.com/elsie" id="link1">three</a>]

对于一些其他属性,可以通过 find_all() 方法的 attrs 参数定义一个字典参数来搜索包含特殊属性的tag:

data_soup.find_all(attrs={"data-foo": "value"})
[<div data-foo="value">foo!</div>]

3、按CSS搜索 (attr, **kwargs)

class_ 参数同样接受不同类型的 过滤器 ,字符串,正则表达式,方法或 True :

soup.find_all("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>]

也可以这样搜索查找:

soup.find_all("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>]

4、text参数 (text)

通过 text 参数可以搜索文档中的字符串内容,与 name 参数的可选值一样,text 参数接受字符串,正则表达式,列表,True :

soup.find_all(text="Elsie")
[u'Elsie']
soup.find_all(text=["Tillie", "Elsie", "Lacie"])
[u'Elsie', u'Lacie', u'Tillie']
soup.find_all(text=re.compile("Dormouse"))

[u"The Dormouse's story", u"The Dormouse's story"]

当然也可以与其他参数混合使用来过滤 tag

soup.find_all("a", text="Elsie")
[<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>]

5、limit参数 (limit)

该参数限制返回数量

soup.find_all("a", limit=2)
[<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]

6、recursive 参数 (recursive)

递归,循环参数。调用tag的 find_all() 方法时,Beautiful Soup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数 recursive=False

7、像调用find_all()一样调用tag

简写方法:

soup.find_all("a")
soup("a")

这两行代码也是等价的:

soup.title.find_all(text=True)
soup.title(text=True)

(五)find()

find(name, attrs, recursive, text, **kwargs)

find()只返回一个结果
下面两行代码是等价的:

>>> soup.find_all('title', limit=1)
[<title>The Dormouse's story</title>]
>>> soup.find('title')
<title>The Dormouse's story</title>

唯一的区别是 find_all() 方法的返回结果是值包含一个元素的列表,而 find() 方法直接返回结果.
find_all() 方法没有找到目标是返回空列表, find() 方法找不到目标时,返回 None .

(六)CSS选择器

可以通过浏览器的审查元素的 copy selector 定位,Beautiful不支持Xpath
在 Tag 或 BeautifulSoup 对象的 .select() 方法中传入字符串参数,即可使用CSS选择器的语法找到tag:

soup.select("title")
[<title>The Dormouse's story</title>]
soup.select("p nth-of-type(3)")
[<p class="story">...</p>]

通过CSS的类名查找:

soup.select(".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>]

soup.select("[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>]

通过tag的id查找:

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

soup.select("a#link2")
[<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]

通过是否存在某个属性来查找:

soup.select('a[href]')
[<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="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>]

(七)get_text()

如果只想得到tag中包含的文本内容,那么可以嗲用 get_text() 方法,这个方法获取到tag中包含的所有文版内容包括子孙tag中的内容,并将结果作为Unicode字符串返回:

>>> markup = '<a href="http://example.com/">\nI linked to <i>example.com</i>\n</a>'
>>> soup = BeautifulSoup(markup, 'lxml')
>>> soup.get_text()
'\nI linked to example.com\n'
>>> soup.i.get_text()  #获取 i 标签内的文本
'example.com'

可以通过参数指定tag的文本内容的分隔符:

soup.get_text("|")
'\nI linked to |example.com|\n'

还可以去除获得文本内容的前后空白:

soup.get_text("|", strip=True)
'I linked to|example.com'

或者使用 .stripped_strings 生成器,获得文本列表后手动处理列表:

[text for text in soup.stripped_strings]
['I linked to', 'example.com']

(八)对 ResultSet 的处理

1、.get_text()
2、.get("href")
3、["href"]
3、.find('span').string
4、.text

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352

推荐阅读更多精彩内容