Python3爬虫神器BeautifulSoup(三)——搜索文档树

搜索文档树里面主要讲find()以及find_all()的用法。在讲这两个用法之前先来说说过滤器,什么过滤器呢?顾名思义,过滤器就是按照条件过滤掉不符合的,留下符合的。那么在Python中这些条件可以是什么呢?我们来依次介绍    

1.字符串(这个没什么好讲的)

2.正则表达式(不知道的可以百度一下什么意思)

3.列表:如果传入列表参数,Beautiful Soup会将与列表中任一元素匹配的内容返回.

4.True:True可以匹配任何值

再来说说方法,什么时候用这个方法呢?当你没有合适的过滤器的时候,那便可以定义一个方法,方法只接受一个元素,如果返回True那么表示当前元素与之匹配并且被找到,反之将会返回false

你可以定义一个寻找包含class但是不包含id的标签

def has_class_but_no_id(tag):

    return tag.has_attr('class') and not tag.has_attr('id')


好了可以来讲讲find_all()和find()了


先来说说.find_all(),它的具体使用规则如下

.find_all(tag,attributes,recursive,text,limit,keywords)

虽然这里有这么多个参数但是其实我们绝大多数时候只使用前两个参数

那么我们一一介绍一下这些参数

tag:就是之前讲的标签名(像<h1>什么之类的),你可以传入一个标签名或者多个 标签组成的列表

attributes:是一个用python字典封装的一个标签的若干属性以及其值,例如:.find_all("span",{"class":{"green","red"}})这就可以找出所有class为green和red的span标签

recursive:是一个递归参数,他是一个布尔变量如果设为True那么会根据要求查找所有子标签以及子标签的子标签,如果设为False那么只会查找文档的一级标签。当然他的默认值是True。一般我们也用不到去修改它。

text:他和attributes有点像但又很是不同,他是用标签里面的文本去匹配而不是标签的属性

limit:只适用于find_all()方法,你可以指定有多少项结果返回过来,要注意的是,设置了limit后返回的是按照顺序返回的,不一定是你想要的结果。

keyword:可以让你选择那些具有指定属性的标签,例如:.find_all(id = "text")这个可以找出所有id=text的标签

但是要记住,不要滥用keyword,keyword只是BeautifulSoup中的一个冗余功能,虽然在有些场景下它显得特别有用,但是任何能够用keyword解决的问题都可以用其他方式解决,

就上一个例子来说

和.find_all("",{"id":"text"})是完全一样的

接下来我们会来说说keyword的一些“缺点”

我们知道class是Python中的一个保留字,是不能当做变量名来使用的。但是HTML标签中经常会有class的属性这时候.find_all(class = "green")就么没有用了。你可以用以下方法解决

.find_all(class_="green")来代替,也就是在class后面加一个_(下划线),但是这个方法显得有点臃肿

我们完全可以用以下方法来代替.find_all("", {"class":"green"})

再顺便说一下,用标签参数将tag以列表的形式传入是或关系的过滤器而keyword的与的选择器

再来说说.find,.find其实就是.find_all()的一种特殊情况,也就是limit = 1的特殊情况。而.find_all()方法是返回一个列表而find方法是直接返回结果

.find_all()和.find只会去搜索子孙节点,如果要搜寻父节点的话那就要用.find_parents()和.find_parent()这个两个的参数和.find_all()和.find()的一样。其中.find_parents()和.parents功效相似,.find_parent()和.parent功效相似。BeautifulSoup还有一些其他的搜索API其中一半是和find()的参数一样一半是和.find_all()的参数一样,

其他的几个分别是(中括号中的是与之功效相似的):

.find_next_siblings()[.next_siblings],.find_next_sibling()[.next_sibling],.find_previous_siblings()[.previous_siblings],.find_previous_sibling()[.previous_sibling],.find_all_next()[.next_elements],.find_next()[.next_element],.find_all_previous()[.previous_elements],.find_previous()[.previous_elements]


CSS选择器

BeautifulSoup对象支持绝大多数CSS选择器,在Tag和BeautifulSoup对象的.select()方法中传入字符串参数就可以找到相应的tag(返回结果一般是列表的形式)那么我们就来说说它的使用方法。

1.可以直接通过标签选择:

                例如(还是以第二篇的那个HTML为例子):

                            soup.select("title")

                            那么就可以得到以下结果:[<title>The Dormouse's story</title>],通过这个方法可以得到所有title标签

                也可以用这个语法:

                             soup.select("p:nth-of-type(3)")

                            那么就可以得到以下的结果:[<p class = "story">....</p>]

                            在这个例子中p:nth-of-type(3)这条语法相当于是选择第三个p标签,相当于soup.select(p)[2])

                我们也可以通过tag逐层寻找:

                            soup.select("body a")这方法可以找到body下所有的a标签

                            也可以用这个soup.select("body > a")(这里的body和>和a之间一定要有空格)这个方法的话可以得到的是body下属的第一个a标签

                也可以来组合一下:

                            soup.select("p > a:nth-of-type(2)")

                当然也会有寻找兄弟节点的方法:

                            soup.select("#link1 ~ .mysis")这个方法可以找到id = link1后的所有兄弟节点标签

                            而这个方法soup.select("#link1 + .mysis")是可以得到id = link1的下一个兄弟标签

2.我们也可以通过类名来寻找

                例如:

                            soup.select(".story")这个方法可以找到所有class为story的标签

                            soup.select("p.sister")这个方法可以找到所有class为story的p标签

3.也可以通过id去查找

                例如:

                            soup.select("#link1")这个方法可以找到所有id = #link的标签

                            soup.select("a#link2")而这个方法可以得到所有id = #link的a标签

4.也可以通过属性来查找

                            一、是否存在某种属性:

                                        soup.select('a[href]')寻找存在href属性的标签

                            二、通过属性的值去寻找:

                                        soup.select('a[href="http://example.com/elsie"]')这条指令可以找到所有href值为http://example.com/elsie的a标签

5.也可以通过语言来设置:

                            看这个例子:

language = """

<p lang = "en">Hello</p>

<p lang = "en-us">Howdy,y'all</p>

<p lang="en-gb">Pip-pip, old fruit</p>

<p lang="fr">Bonjour mes amis</p>

"""

soup = BeautifulSoup(language,'lxml')

soup.select('p[lang|=en]')这条指令可以得到一下结果:[<p lang= "en">Hello</p>,<p lang="en-us">Howdy,y'all</p>,<p lang="en-gb">Pip-pip, old fruit</p>]

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

推荐阅读更多精彩内容