BeautifulSoup4和JsonPath

BeautifulSoup4和JsonPath

BeautifulSoup4

  • BeautifulSoup可以從HTML、XML中提取數據,目前BS4在持續開發。

  • 官方中文文檔https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/

  • 安裝

    1. pip install beautifulsoup4
  • 導入:from bs4 import BuautifulSoup

  • 初始化:

    1. BeautifulSoup(markup="",features=None)
      • markup,被解析對象,可以是文件對象或者html字符串
      • feature指定解析器
      • return:返回一個文檔對象
from bs4 import BeautifulSoup

#文件對象
soup = BeautifulSoup(open("test.html"))
# 標記字符串
soup = BeautifulSoup("<html>data</html>")
  • 可以不指定解析器,就依賴系統已經安裝的解析器庫了。
解析器 使用方法 優勢 劣勢
Python標準庫 BeautifulSoup(markup,“html.parser”) Python的內置標準庫
執行速度適中
文檔容錯能力強
Python 2.7.3、3.2.2前 的版本中文檔容錯能力差
lxml HTML 解析器 BeautifulSoup(markup,“lxml”) 速度快
文檔容錯能力強
需要安裝C語言庫
lxml XML 解析器 BeautifulSoup(markup,[“lxml”,“xml”])
BeautifulSoup(markup,“xml”)
速度快
唯一支持XML的解析器
需要安裝C語言庫
html5lib BeautifulSoup(markup,“html5lib”) 最好的容錯性
以瀏覽器的方式解析文檔
生成HTML5格式的文檔
速度慢
不依賴外部擴展
  • BeautifulSoup(markup,“html.parser”)使用Python標準庫,容錯差且性能一般。
  • BeautifulSoup(markup,“lxml”)容錯能力強,速度快。需要安裝系統C庫。
  • 推薦使用lxml作爲解析器,效率高。
  • 需要手動指定解析器,以保證代碼在所有運行環境中解析器一致。
  1. 使用下面內容構建test.html使用bs4解析它
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首頁</title>
</head>
<body>
<h1>xdd歡迎您</h1>
<div id="main">
    <h3 class="title highlight"><a href="http://www.python.org">python</a>高級班</h3>
    <div class="content">
        <p id="first">字典</p>
        <p id="second">列表</p>
        <input type="hidden" name="_csrf" value="absdoia23lkso234r23oslfn">
        <!-- comment -->
        <img id="bg1" src="http://www.xdd.com/">
        <img id="bg2" src="http://httpbin.org/">
    </div>
</div>
<p>bottom</p>
</body>
  • 四種對象
  1. BeautifulSoup將HTML文檔解析成複雜的樹型結構,每個節點都是Python的對象,可分爲4種:
    • BeautifulSoup、Tag、NavigableString、Comment
    1. BeautifulSoup對象:代表整個文檔。
    2. Tag對象:對應着HTML中的標籤。有2個常用的屬性:
      1. name:Tag對象的名稱,就是標籤名稱
      2. attrs:標籤的屬性字典
        • 多值屬性,對於class屬性可能是下面的形式,<h3 class="title highlight">python高級班</h3>這個屬性就是多值({“class”:[“title”,“highlight”]})
        • 屬性可以被修改、刪除
  • BeautifulSoup.prettify() #帶格式輸出解析的文檔對象(即有縮進的輸出),注意:直接輸出BeautifulSoup會直接輸出解析的文檔對象,沒有格式。
  • BeautifulSoup.div #輸出匹配到的第一個div對象中的內容,返回對象是bs4.element.Tag類型
  • BeautifulSoup.h3.get(“class”) #獲取文檔中第一個標籤爲h3對象中class屬性值
from bs4 import BeautifulSoup

with open("d://xdd.html",encoding="utf-8") as f:
    soup = BeautifulSoup(f,"lxml")
    print(soup.builder)
    # print(0,soup) #輸出整個解析的文檔對象(不帶格式)
    # print(1,soup.prettify()) #按照格式輸出文檔內容
    print("- "*30)
    # print(2,soup.div,type(soup.div)) #類型bs4.element.Tag,Tag對象
    # print(3,soup.div["class"]) #會報錯,keyError,div沒有class屬性
    print(3,soup.div.get("class")) #獲取div的class屬性,沒有返回None

    print(4,soup.div.h3["class"]) #多值屬性
    print(4,soup.h3.get("class")) #多值屬性,獲取文檔中第一h3標籤中的class屬性
    print(4,soup.h3.attrs.get("class")) #多值屬性

    print(5,soup.img.get("src")) #獲取img中src屬性值
    soup.img["src"] = "http://www.xddupdate.com" #修改值
    print(5,soup.img["src"])

    print(6,soup.a) #找不到返回None
    del soup.h3["class"] #刪除屬性
    print(4,soup.h3.get("class"))

bsoup_001

  • 注意:我們一般不使用聲明這種方式來操作HTML,此代碼時爲了熟悉對象類型

  • NavigableString

  1. 如果只想輸出標記的文本,而不關心標記的話,就要使用NavigableString.
print(soup.div.p.string) #第一個div下第一個p的字符串
print(soup.p.string) #同上
  • 註釋對象:這就是HTML中的註釋,它被BeautifulSoup解析後對應Comment對象。

遍歷文檔樹

  • 在文檔樹中找到關心的內容纔是日常的工資,也就是說如何遍歷樹中的節點。使用上面的test.html來測試
  1. 使用Tag

    • soup.div可以找到從根節點開始查找第一個div節點,返回一個Tag對象
    • soup.div.p說明從根節點開始找到第一個div後返回一個Tag對象,這個Tag對象下繼續找第一個p,找到返回Tag對象
    • soup.p返回了文字“字典”,而不是文字“bottom"說明遍歷時深度優先,返回也是Tag對象
  2. 遍歷直接子節點

    • Tag.contents #將對象的所有類型直接子節點以列表方式輸出
    • Tag.children #返回子節點的迭代器
      • Tag.children #等價於Tag.contents
  3. 遍歷所有子孫節點

    • Tag.descendants #返回節點的所有類型子孫節點,可以看出迭代次序是深度優先
    from bs4 import BeautifulSoup
    from bs4.element import Tag
    
    with open("d://xdd.html",encoding="utf-8") as f:
        soup = BeautifulSoup(f,"lxml")
        print(soup.p.string)
        print(soup.div.contents) #直接子標籤列表
        print("- "*30)
    
        for i in soup.div.children: #直接子標籤可迭代對象
            print(i.name)
        print("- "*30)
        print(list(map(
            lambda x:x.name if x.name else x,
            soup.div.descendants #所有子孫
        )))
    

bsoup_002

  1. 遍歷字符串

    • 在前面的例子中,soup.div.string返回None,是因爲string要求soup.div只能有一個NavigableString類型子節點,也就是這樣<div>only string</div>
    • Tag.string #獲取Tag下的string對象,如果多餘1個結點返回None
    • Tag.strings #返回迭代器,帶多餘的空白字符。所有的string對象
    • Tag.stripped_strings #返回,會去除多餘空白字符
    from bs4 import BeautifulSoup
    from bs4.element import Tag
    
    with open("d://xdd.html",encoding="utf-8") as f:
        soup = BeautifulSoup(f,"lxml")
        print(soup.div.string) #返回None,因爲多餘1個子節點
        print("- "*30)
        print("".join(soup.div.strings).strip()) #返回迭代器,帶多餘的空白字符
        print("- "*30)
        print("".join(soup.div.stripped_strings)) #返回迭代器,去除多餘空白字符
    

bsoup_003

  1. 遍歷祖先節點

    • BeautifulSoup.parent #獲取根節點的父結點,必定返回None,根節點沒有父結點
    • Tag.parent #獲取第一個Tag的父結點
    • Tag.parent.parent.get(“id”) #獲取第一個tag的父結點的父結點的id屬性
    • Tag.parents #獲取Tag節點的所有父結點,由近及遠
    from bs4 import BeautifulSoup
    from bs4.element import Tag
    
    with open("d://xdd.html",encoding="utf-8") as f:
        soup = BeautifulSoup(f,"lxml")
        print(type(soup))
        print(soup.parent)
        print(soup.div.parent.name) #body ,第一個div的父節點
        print(soup.p.parent.parent.get("id")) #取id屬性, main
        print("- "*30)
        print(list(map(lambda x:x.name,soup.p.parents))) #父迭代器,由近及遠
    

bsoup_004

  1. 遍歷兄弟節點

    • Tag.next_sibling #第一個Tag元素的下一個(下面)兄弟節點,注意:可能是一個文本節點
    • Tag.previous_sibling #第一個Tag元素之前的兄弟節點(上面),注意:可能是一個文本節點
    • Tag.next_siblings #獲取Tag元素的下面的所有兄弟節點
    from bs4 import BeautifulSoup
    from bs4.element import Tag
    
    with open("d://xdd.html",encoding="utf-8") as f:
        soup = BeautifulSoup(f,"lxml")
        print(type(soup),type(soup.p))
        print("{} [{}]".format(1,soup.p.next_sibling.encode()))
        print("{} [{}]".format(2,soup.p.previous_sibling.encode()))
        print(soup.p.previous_sibling.next_sibling) #等價於soup.p
        print(soup.p.next_sibling.previous_sibling)  # 等價於soup.p
        print(soup.p)
        print(list(soup.p.next_siblings))
    

bsoup_005

  1. 遍歷其他元素

    • Tag.next_element #是下一個可被解析的對象(字符串或tag),和下一個兄弟節點next_sibling不一樣
    • Tag.next_elements #返回所有下一個可被解析的對象,是個可迭代對象。
    from bs4 import BeautifulSoup
    
    with open("d://xdd.html",encoding="utf-8") as f:
        soup = BeautifulSoup(f,"lxml")
        print(type(soup),type(soup.p))
        print(soup.p.next_element) #返回"字典"2個字
        print(soup.p.next_element.next_element.encode())
        print(soup.p.next_element.next_element.next_element)
        print(list(soup.p.next_elements))
    
        print("- "*30)
        #對比差異
        print(list(soup.p.next_elements))
        print(list(soup.p.next_siblings))
    

bsoup_006

搜索文檔樹

  1. name參數:官方稱爲fiter過濾器,這個參數可以是一下

    1. 字符串:一個標籤名稱的字符串,會按照這個字符串全長匹配標籤名
      print(soup.find_all('p'))#返回文檔中所有p標籤

    2. 正則表達式對象:按照"正則表達式對象"的模式匹配標籤名

      import re
      print(soup.find_all(re.compile("^h\d"))) #標籤名以h開頭後接數字
      
    3. 列表:或關係查找列表中的每個字符串

      print(soup.find_all(["p","h1","h3"])) #或關係,找出列表所有的標籤
      print(soup.find_all(re.compile(r"^p|h|\d$"))) #使用正則表達式完成
      
    4. True或None,則find_all返回全部非字符串節點、非註釋節點,就是Tag標籤類型

      from bs4 import BeautifulSoup
      
      with open("d://xdd.html",encoding="utf-8") as f:
          soup = BeautifulSoup(f,"lxml")
          print(list(map(lambda x: x.name, soup.find_all(True))))
          print(list(map(lambda x: x.name, soup.find_all(None))))
          print(list(map(lambda x: x.name, soup.find_all())))
      

    bsoup_007

     ````python
     from bs4 import BeautifulSoup
     from bs4.element import Tag
    
     with open("d://xdd.html",encoding="utf-8") as f:
         soup = BeautifulSoup(f,"lxml")
         values = [True,None,False]
         for value in values:
             all = soup.find_all(value)
             print(type(all[0]))
             print(len(all))
    
         print("- "*30)
         count = 0
         for i,t in enumerate(soup.descendants): #遍歷所有類型的子孫節點
             print(i,type(t),t.name)
             if isinstance(t,Tag): #只對Tag類型計數
                 count += 1
         print(count)
     # 數目一致,所以返回的是Tag類型的節點,源碼中確實返回的Tag類型
     ````
    
     ![bsoup_008](https://img-blog.csdnimg.cn/20190820210855938.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTMwMDg3OTU=,size_16,color_FFFFFF,t_70)
    
    1. 函數

      • 如果使用以上過濾器還不能提取想要的節點,可以使用函數,此函數僅只能接收一個參數
      • 如果這個函數返回True,表示當前節點配置;返回False則是不匹配。
      1. 示例:找出所有class屬性且有多個值的節點(測試html中符合這個條件只有h3標籤)
      from bs4 import BeautifulSoup
      from bs4.element import Tag
      
      def many_classes(tag:Tag):
          # print(type(tag))
          # print(type(tag.attrs))
          return len(tag.attrs.get("class",[])) > 1
      
      with open("d://xdd.html",encoding="utf-8") as f:
          soup = BeautifulSoup(f,"lxml")
          print(soup.find_all(many_classes))
      

      bsoup_009

  2. keyword傳參

    1. 使用關鍵字傳參,如果參數名不是find系函數已定義的位置參數名,參數會被kwargs收集並被當做標籤的屬性來搜索。
    2. 屬性的傳參可以是字符串、正則表達式對象、True、列表。
    from bs4 import BeautifulSoup
    import re
    
    with open("d://xdd.html",encoding="utf-8") as f:
        soup = BeautifulSoup(f,"lxml")
        print(soup.find_all(id="first")) #id爲first的所有結點列表
        print(1,"- "*30)
        print(soup.find_all(id=re.compile("\w+"))) #相當於找有di的所有節點
        print(2,"- " * 30)
        print(soup.find_all(id=True)) #所有有id的節點
    
        print(3,"- " * 30)
        print(list(map(lambda x:x["id"],soup.find_all(id=True))))
        print(4,"- " * 30)
        print(soup.find_all(id=["first",re.compile(r"^sec")])) #指定id的名稱列表
        print(5,"- " * 30)
        print(soup.find_all(id=True,src=True)) #相當於條件and,既有id又有src屬性的節點列表
    

    bsoup_010

  3. css的class的特殊處理

    1. class是Python關鍵字,所以使用class_。class是多值屬性,可以匹配其中任意一個,也可以完全匹配。
    print(soup.find_all(class_="content"))
    print(soup.find_all(class_="title")) #可以使用任意一個css類
    print(soup.find_all(class_="highlight")) #可以使用任意一個css類
    print(soup.find_all(class_="highlight title")) #順序錯了,找不到
    print(soup.find_all(class_="title highlight")) #順序一致,找到。就是字符串完全匹配
    
  4. attrs參數

    • attrs接收一個字典,字典的key爲屬性名,value可以是字符串、正則表達式對象、True、列表。可以多個屬性
    print(soup.find_all(attrs={"class":"title"}))
    print(soup.find_all(attrs={"class":"highlight"}))
    print(soup.find_all(attrs={"class":"title highlight"}))
    print(soup.find_all(attrs={"id":True}))
    print(soup.find_all(attrs={"id":re.compile(r"\d$")}))
    print(list(map(lambda x:x.name,soup.find_all(attrs={"id":True,"src":True}))))
    
  5. text參數

    • 可以通過text參數搜索文檔中的字符串內容,接受字符串、正則表達式對象、True、列表
    from bs4 import BeautifulSoup
    import re
    
    with open("d://xdd.html",encoding="utf-8") as f:
        soup = BeautifulSoup(f,"lxml")
        print(list(map(lambda x:(type(x),x),soup.find_all(text=re.compile("\w+"))))) #返回文本類節點
        print("- "*30)
        print(list(map(lambda x:(type(x),x),soup.find_all(text=re.compile("[a-z]+")))))
        print("- "*30)
        print(soup.find_all(re.compile(r"^(h|p)"),text=re.compile("[a-z]+"))) #相當於過濾Tag對象,並看它的string是否符合text參數要求,返回Tag對象
    

    bsoup_011

  6. limit參數:顯示返回結果的數量

    print(soup.find_all(id=True,limit=3)) #返回列表中有3個結果
    
  7. recursive參數

    • 默認是遞歸搜索所有子孫節點,如果不需要請設置爲False
  • 簡化寫法

    1. find_all()是非常常用的方法,可以簡化省略掉
    from bs4 import BeautifulSoup
    import re
    
    with open("d://xdd.html",encoding="utf-8") as f:
        soup = BeautifulSoup(f,"lxml")
        print(soup("img")) #所有img標籤對象的列表,等價於soup.find_all("img")
        print(soup.img) #深度優先第一個img
    
        print(soup.a.find_all(text=True)) #返回文本
        print(soup.a(text=True)) #返回文本,和上面等價
        print(soup("a",text=True)) #返回a標籤對象
    
        print(soup.find_all("img",attrs={"id":"bg1"}))
        print(soup("img",attrs={"id":"bg1"})) #find_all的省略
        print(soup("img",attrs={"id":re.compile("1")}))
    

    bsoup_012

  • find方法

    1. find(name,attrs,recursive,text,**kwargs)
      • 參數幾乎和find_all一樣。
      • 找到了,find_all返回一個列表,而find返回一個單值,元素對象。
      • 找不到,find_all返回一個空列表,而find返回一個None。
    from bs4 import BeautifulSoup
    
    with open("d://xdd.html",encoding="utf-8") as f:
        soup = BeautifulSoup(f,"lxml")
        print(soup.find("img",attrs={"id":"bg1"}).attrs.get("src","xdd"))
        print(soup.find("img",attrs={"id":"bg1"}).get("src")) #簡化了attrs
        print(soup.find("img",attrs={"id":"bg1"})["src"])
    

    bsoup_013

CSS選擇器

  • 和JQuery一樣,可以使用CSS選擇器來 查找節點
  • 使用soup.select()方法,select方法支持大部分CSS選擇器,返回列表。
  • CSS中,標籤名直接使用,類名前加.點號,id名前加#井號。
  1. BeautifulSoup.select(“css選擇器”)
from bs4 import BeautifulSoup

with open("d://xdd.html",encoding="utf-8") as f:
    soup = BeautifulSoup(f,"lxml")
    #元素選擇器
    print(1,soup.select("p")) #所有的p標籤

    #類選擇器
    print(2,soup.select(".title"))

    #使用了僞類
    #直接子標籤是p的同類型的所有p標籤中的第二個
    #(同類型)同標籤名p的第2個,僞類只實現了nth-of-type,且要求是數字
    print(3,soup.select("div.content >p:nth-of-type(2)"))

    # id選擇器
    print(4,soup.select("p#second"))
    print(5,soup.select("#bg1"))

    #後代選擇器
    print(6,soup.select("div p")) # div下逐層找p
    print(7,soup.select("div div p")) #div下逐層找div下逐層找p

    #子選擇器,直接後代
    print(8,soup.select("div > p")) #div下直接子標籤的p,有2個

    #相鄰兄弟選擇器
    print(9, soup.select("div p:nth-of-type(1) + [src]")) #返回[]
    print(9, soup.select("div p:nth-of-type(1) + p"))  # 返回p標籤
    print(9, soup.select("div > p:nth-of-type(2) + input"))  # 返回input Tag
    print(9, soup.select("div > p:nth-of-type(2) + [type]"))  # 同上

    #普通兄弟選擇器
    print(10, soup.select("div p:nth-of-type(1) ~ [src]")) #返回2個img

    #屬性選擇器
    print(11,soup.select("[src]")) #有屬性src
    print(12,soup.select("[src='/']")) #屬性src等於/
    print(13,soup.select("[src='http://www.xdd.com/']")) #完全匹配
    print(14,soup.select("[src^='http://www']")) #以http://www開頭
    print(15,soup.select("[src$='com/']")) #以com/結尾
    print(16,soup.select("img[src*='xdd']")) #包含xdd
    print(17,soup.select("img[src*='.com']")) #包含.com
    print(18,soup.select("[class='title highlight']")) #完全匹配calss等於'title highlight'
    print(19,soup.select("[class~=title]")) #多值屬性中有一個title

bsoup_014

  • 獲取文本內容
  1. 搜索節點的目的往往是爲了提取該節點的文本內容,一般不需要HTML標記,只需要文字
from bs4 import BeautifulSoup

with open("d://xdd.html",encoding="utf-8") as f:
    soup = BeautifulSoup(f,"lxml")
    # 元素選擇器
    ele = soup.select("div") #所有的div標籤
    print(type(ele))
    print(ele[0].string) #內容僅僅只能是文本類型,否則返回None
    print(list(ele[0].strings)) #迭代保留空白字符
    print(list(ele[0].stripped_strings)) #迭代不保留空白字符

    print("- "*30)
    print(ele[0])
    print("- " * 30)

    print(list(ele[0].text))#本質上就是get_text(),保留空白字符的strings
    print(list(ele[0].get_text())) #迭代並join,保留空白字符,strip默認爲False
    print(list(ele[0].get_text(strip=True))) #迭代並join,不保留空白字符

bsoup_015

  • bs4.element.Tag#string源碼
class Tag(PageElement):
@property
    def string(self):
        if len(self.contents) != 1:
            return None
        child = self.contents[0]
        if isinstance(child, NavigableString):
            return child
        return child.string

    @string.setter
    def string(self, string):
        self.clear()
        self.append(string.__class__(string))

    def _all_strings(self, strip=False, types=(NavigableString, CData)):
        for descendant in self.descendants:
            if (
                (types is None and not isinstance(descendant, NavigableString))
                or
                (types is not None and type(descendant) not in types)):
                continue
            if strip:
                descendant = descendant.strip()
                if len(descendant) == 0:
                    continue
            yield descendant

    strings = property(_all_strings)

    @property
    def stripped_strings(self):
        for string in self._all_strings(True):
            yield string

    def get_text(self, separator="", strip=False,
                 types=(NavigableString, CData)):
        return separator.join([s for s in self._all_strings(
                    strip, types=types)])
    getText = get_text
    text = property(get_text)

Json解析

  • 拿到一個Json字符串,如果想提取其中的部分內容,就需要遍歷了。在遍歷過程中進行判斷。
  • 還有一種方式,類似於XPath,叫做jsonPath。
  • 安裝pip install jsonpath
  • 官網https://goessner.net/articles/JsonPath/
XPath JsonPath 說明
/ $ 根元素
. @ 當前節點
/ .或者[] 獲取子節點
.. 不支持 父節點
// .. 任意層次
* * 通配符,匹配任意節點
@ 不支持 json中沒有屬性
[] [] 下標操作
| [,] XPath是或操作,JSONPath allows alternate names or array indices as a set.
不支持 [start:stop:step] 切片
[] ?() 過濾操作
不支持 () 表達式計算
() 不支持 分組
{
    "subjects":[
        {
            "rate":"8.8",
            "cover_x":1500,
            "title":"寄生蟲",
            "url":"https://movie.douban.com/subject/27010768/",
            "playable":false,
            "cover":"https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2561439800.jpg",
            "id":"27010768",
            "cover_y":2138,
            "is_new":false
        },
        {
            "rate":"7.7",
            "cover_x":1500,
            "title":"惡人傳",
            "url":"https://movie.douban.com/subject/30211551/",
            "playable":false,
            "cover":"https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2555084871.jpg",
            "id":"30211551",
            "cover_y":2145,
            "is_new":false
        },
        {
            "rate":"6.6",
            "cover_x":1500,
            "title":"異地母子情",
            "url":"https://movie.douban.com/subject/26261189/",
            "playable":false,
            "cover":"https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2562107493.jpg",
            "id":"26261189",
            "cover_y":2222,
            "is_new":true
        },
        {
            "rate":"6.7",
            "cover_x":2025,
            "title":"我的生命之光",
            "url":"https://movie.douban.com/subject/26962841/",
            "playable":false,
            "cover":"https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2563625370.jpg",
            "id":"26962841",
            "cover_y":3000,
            "is_new":true
        },
        {
            "rate":"7.3",
            "cover_x":2025,
            "title":"皮膚",
            "url":"https://movie.douban.com/subject/27041467/",
            "playable":false,
            "cover":"https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2559479239.jpg",
            "id":"27041467",
            "cover_y":3000,
            "is_new":true
        },
        {
            "rate":"8.9",
            "cover_x":2000,
            "title":"綠皮書",
            "url":"https://movie.douban.com/subject/27060077/",
            "playable":true,
            "cover":"https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2549177902.jpg",
            "id":"27060077",
            "cover_y":3167,
            "is_new":false
        },
        {
            "rate":"8.0",
            "cover_x":3600,
            "title":"疾速備戰",
            "url":"https://movie.douban.com/subject/26909790/",
            "playable":false,
            "cover":"https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2551393832.jpg",
            "id":"26909790",
            "cover_y":5550,
            "is_new":false
        },
        {
            "rate":"7.9",
            "cover_x":1786,
            "title":"流浪地球",
            "url":"https://movie.douban.com/subject/26266893/",
            "playable":true,
            "cover":"https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2545472803.jpg",
            "id":"26266893",
            "cover_y":2500,
            "is_new":false
        },
        {
            "rate":"8.2",
            "cover_x":684,
            "title":"淪落人",
            "url":"https://movie.douban.com/subject/30140231/",
            "playable":false,
            "cover":"https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2555952192.jpg",
            "id":"30140231",
            "cover_y":960,
            "is_new":false
        },
        {
            "rate":"6.4",
            "cover_x":960,
            "title":"瘋狂的外星人",
            "url":"https://movie.douban.com/subject/25986662/",
            "playable":true,
            "cover":"https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2541901817.jpg",
            "id":"25986662",
            "cover_y":1359,
            "is_new":false
        }
    ]
}
from jsonpath import jsonpath
import requests
import json

ua = "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN) AppleWebKit/537.36 (KHTML, like Gecko) Version/5.0.1 Safari/537.36"
url = "https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&page_limit=10&page_start=0"

with requests.get(url,headers={"User-agent":ua}) as response:
    if response.status_code==200:
        text = response.text
        print(text[:100])
        js = json.loads(text)
        print(str(js)[:100]) #json轉換爲Python數據結構

        #知道所有電影的名稱
        rs1 = jsonpath(js,"$..title") #從根目錄開始,任意層次的title屬性
        print(rs1)

        #找到所有subjects
        rs2 = jsonpath(js,"$..subjects")
        print(len(rs2),str(rs2[0])[:100]) #由於太長,取前100個字符

        print("- " * 30)
        # 找到所有得分高於8分的電影名稱
        # 根下任意層的subjects的子節點rate大於字符串8
        rs3 = jsonpath(js,'$..subjects[?(@.rate > "8")]') #?()是過濾器
        print(rs3)

        print("- "*30)
        #根下任意層的subjects的子節點rate大於字符串8的節點的子節點title
        rs4 = jsonpath(js,'$..subjects[?(@.rate > "8")].title')
        print(rs4)
        print("- " * 30)

        #切片
        rs5 = jsonpath(js,"$..subjects[?(@.rate > '6')].title")
        print(rs5[:2])

bsoup_016

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章