基础学习——BeautifulSoup篇(2)

这一篇文章接在上一篇 基础学习——BeautifulSoup篇(1) 之后,今天来继续学习BeautifulSoup

欢迎关注公众号:老白和他的爬虫

4.遍历文档树

4.7父节点和兄弟节点

父节点可以通过.parent.parents操作得倒

from bs4 import BeautifulSoup
if __name__ == "__main__":
     html_doc = """
        <html><head><title>The Dormouse's story</title></head>
        <p class="title"><b>The Dormouse's story</b></p>
        <p class="story">Once upon a time there were three little sisters; and their names were
        <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
        <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
        <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
        and they lived at the bottom of a well.</p>
        <p class="story">...</p>
        """
     soup = BeautifulSoup(html_doc,'lxml')
     head_tag = soup.head
     title_tag = head_tag.contents[0]
     print(title_tag.parent) #打印title_tag的父节点
     link = soup.a
     for parent in link.parents: #循环打印a标签的父节点
         if parent is None:
             print(parent)
         else:
             print(parent.name)

兄弟节点些微有点不同,一个节点可以通过.next_sibling.previous_sibling得到它之前和之后的兄弟节点,同样,也可以通过.next_siblings.previous_siblings遍历操作得倒所有的兄弟节点。

4.8回退和缩进

上一个内容讲的.next_sibling.previous_sibling其实就已经有了缩进和回退的味道了,但是他们是不同的。我们使用解析器把html文档解析成了一个又一个事件或者说是标签,兄弟节点只能在这一级进行前后操作,然而要对整个文档进行操作,我们就必须使用到.next_element.previous_element。我们用上面的文档树来举一个例子

last_a_tag = soup.find("a", id="link2")
print(last_a_tag.next_sibling) 
print(last_a_tag.next_element) 

print(last_a_tag.next_sibling)的输出结果是and因为第二个<a>下一个兄弟节点是and,但是print(last_a_tag.next_element)的输出结果是Lacie,因为第二个<a>下一个元素是比它低一级的字符串Lacie。这段代码理解的画,这两个操作也很好理解了,同理它还有.next_elements.previous_elements这两个操作,具体怎么用不用我说了吧,类比一下就会了。

4.9. find_all()

find_all(name , attrs , text , keyword )使用.find_all()操作可以设置这些常用参数

4.9.1 name参数

.find_all()可以直接查找tag的name来找到对应的标签

soup.find_all('b') #用来查找所有的<b>标签

4.9.2 keyword参数.find_all()``.find_all()

print(soup.find_all(id='link2')) #用来查找id为link2的标签

.find_all()操作可以与正则表达式搭配,个人认为这一步在查找一些特定标签时十分有用

import re
     #找到所有标签中以b开头的标签
     for tag in soup.find_all(re.compile("^b")):
         print(tag.name)
     #提取所有a标签中包含字符串example的链接
     for x in soup.find_all('a',href = re.compile('example')):
         print(x.get('href'))

这里记住一点,.find_all()内部的多个参数是可以同时写的,上面这段代码我这样写也可以

for x in soup.find_all(class_ = 'sister' ,href = re.compile('example')):
         print(x.get('href'))

class应该是python的关键字,所以我们这里需要用class_来表示class

4.9.3 attrs参数

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

data_soup = BeautifulSoup('<div data-foo="value">foo!</div>','lxml')
     print(data_soup.find_all(attrs={"data-foo": "value"}))

4.9.4 text参数

     print(soup.find_all(text="Elsie")) #输出文本为Elsie的字符串
     print(soup.find_all(text=["Tillie", "Elsie", "Lacie"])) #输出文本为列表中所包含的字符串
     print(soup.find_all(text=re.compile("Dormouse"))) #输出文本包含Dormouse的字符串

4.9.5 limit参数

limit参数可以限制返回节点的数量

    print(soup.find_all('a',limit = 2)) #本身可以返回三个a标签,但是由于limit限制只返回两个

4.10 find()

.find()其实就是.find_all()加上了limit = 1的操作,区别于.find()返回的是结果,.find_all()返回的是集合
.find().find_all()还有其他的一些操作,这里就不一一举例了,避免这个教程太过繁琐,只要熟练的掌握.find().find_all(),就已经能解决很多的问题。其他的一些操作包括
find_parents(),find_parent(),find_next_siblings(),find_next_sibling(),find_previous_siblings(),find_previous_sibling(),find_all_next(),find_next(),find_all_previous(),find_previous()

4.11 CSS选择器

这一个功能我不打算在这里说,因为这里能实现的功能在前面我们都已经实现了,只不过更熟悉css的人可以选择这种方法。

5.修改文档树

给tag的 .string属性赋值,就相当于用当前的内容替代了原来的内容:

     markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
     soup = BeautifulSoup(markup,'lxml')
     tag = soup.a
     tag.string = "New link text."
     print(tag)

使用.append()方法可以像标签添加内容

     markup = '<a href="http://example.com/">I linked to </a>'
     soup = BeautifulSoup(markup,'lxml')
     tag = soup.a
     print(tag)
     tag.append("haha")
     print(tag)

如果想要创建一段注释

     from bs4 import Comment
     new_comment = soup.new_string("Nice to see you.", Comment)
     tag.append(new_comment)
     print(tag)

如果想要创建一个新的tag

     soup = BeautifulSoup("<b></b>",'lxml')
     original_tag = soup.b
     new_tag = soup.new_tag("a", href="http://www.example.com")
     original_tag.append(new_tag)
     print(original_tag)
     new_tag.string = "Link text."
     print(original_tag)
    

使用'.insert()'插入具体的内容

     markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
     soup = BeautifulSoup(markup,'lxml')
     tag = soup.a
     tag.insert(1, "but did not endorse ") #参数1控制插入字符串的位置
     print(tag)

移除当前tag的内容

     tag.clear()
     print(tag)

移除当前的tag节点

     a_tag = soup.a
     i_tag = soup.i.extract()
     print(a_tag)
     print(i_tag)

使用decompose()完全销毁当前tag节点

     markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
     soup = BeautifulSoup(markup,'lxml')
     tag = soup.a
     a_tag = soup.a
     soup.i.decompose()
     print(a_tag)

使用replace_with()替换节点

     markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
     soup = BeautifulSoup(markup,'lxml')
     tag = soup.a
     a_tag = soup.a
     new_tag = soup.new_tag("b")
     new_tag.string = "example.net"
     a_tag.i.replace_with(new_tag)
     print(tag)

6.输出

.prettify()方法将BeautifulSoup的文档树格式化后以Unicode编码输出,每个XML/HTML标签都独占一行

     markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
     soup = BeautifulSoup(markup,'lxml')
     print(soup.prettify())

如果不想格式化输出,可以选择压缩输出

     print(str(soup))

如果只想得到标签中的文本内容

     markup = '<a href="http://example.com/">\nI linked to <i>example.com</i>\n</a>'
     soup = BeautifulSoup(markup,'lxml')
     print(soup.get_text())
     print(soup.get_text("|")) #指定文本分隔符
     print(soup.get_text("|", strip=True)) #去除文本内容前后空白

好了,BeautifulSoup的基础知识我们已经学习完毕了,你可以跟着这两篇文章来学习掌握BeautifulSoup,也可以选择把这两篇当作字典,当你在写爬虫时来翻阅

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

推荐阅读更多精彩内容