BeautifulSoup4和JsonPath
BeautifulSoup4
-
BeautifulSoup可以從HTML、XML中提取數據,目前BS4在持續開發。
-
官方中文文檔https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/
-
安裝
pip install beautifulsoup4
-
導入:
from bs4 import BuautifulSoup
-
初始化:
- BeautifulSoup(markup="",features=None)
- markup,被解析對象,可以是文件對象或者html字符串
- feature指定解析器
- return:返回一個文檔對象
- BeautifulSoup(markup="",features=None)
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作爲解析器,效率高。
- 需要手動指定解析器,以保證代碼在所有運行環境中解析器一致。
- 使用下面內容構建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>
- 四種對象
- BeautifulSoup將HTML文檔解析成複雜的樹型結構,每個節點都是Python的對象,可分爲4種:
- BeautifulSoup、Tag、NavigableString、Comment
- BeautifulSoup對象:代表整個文檔。
- Tag對象:對應着HTML中的標籤。有2個常用的屬性:
- name:Tag對象的名稱,就是標籤名稱
- attrs:標籤的屬性字典
- 多值屬性,對於class屬性可能是下面的形式,
<h3 class="title highlight">python高級班</h3>
這個屬性就是多值({“class”:[“title”,“highlight”]}) - 屬性可以被修改、刪除
- 多值屬性,對於class屬性可能是下面的形式,
- 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"))
-
注意:我們一般不使用聲明這種方式來操作HTML,此代碼時爲了熟悉對象類型
-
NavigableString
- 如果只想輸出標記的文本,而不關心標記的話,就要使用NavigableString.
print(soup.div.p.string) #第一個div下第一個p的字符串
print(soup.p.string) #同上
- 註釋對象:這就是HTML中的註釋,它被BeautifulSoup解析後對應Comment對象。
遍歷文檔樹
- 在文檔樹中找到關心的內容纔是日常的工資,也就是說如何遍歷樹中的節點。使用上面的test.html來測試
-
使用Tag
- soup.div可以找到從根節點開始查找第一個div節點,返回一個Tag對象
- soup.div.p說明從根節點開始找到第一個div後返回一個Tag對象,這個Tag對象下繼續找第一個p,找到返回Tag對象
- soup.p返回了文字“字典”,而不是文字“bottom"說明遍歷時深度優先,返回也是Tag對象
-
遍歷直接子節點
- Tag.contents #將對象的所有類型直接子節點以列表方式輸出
- Tag.children #返回子節點的迭代器
- Tag.children #等價於Tag.contents
-
遍歷所有子孫節點
- 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 #所有子孫 )))
-
遍歷字符串
- 在前面的例子中,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)) #返回迭代器,去除多餘空白字符
- 在前面的例子中,soup.div.string返回None,是因爲string要求soup.div只能有一個NavigableString類型子節點,也就是這樣
-
遍歷祖先節點
- 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))) #父迭代器,由近及遠
-
遍歷兄弟節點
- 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))
-
遍歷其他元素
- 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))
搜索文檔樹
-
find繫有很多分發,請執行查詢幫助https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/#id25
-
find_all(name=None,attrs={},recursive=True,text=None,limit=None,**kwargs)
#立即返回一個列表
-
name參數:官方稱爲fiter過濾器,這個參數可以是一下
-
字符串:一個標籤名稱的字符串,會按照這個字符串全長匹配標籤名
print(soup.find_all('p'))
#返回文檔中所有p標籤 -
正則表達式對象:按照"正則表達式對象"的模式匹配標籤名
import re print(soup.find_all(re.compile("^h\d"))) #標籤名以h開頭後接數字
-
列表:或關係查找列表中的每個字符串
print(soup.find_all(["p","h1","h3"])) #或關係,找出列表所有的標籤 print(soup.find_all(re.compile(r"^p|h|\d$"))) #使用正則表達式完成
-
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())))
````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)
-
函數
- 如果使用以上過濾器還不能提取想要的節點,可以使用函數,此函數僅只能接收一個參數。
- 如果這個函數返回True,表示當前節點配置;返回False則是不匹配。
- 示例:找出所有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))
-
-
keyword傳參
- 使用關鍵字傳參,如果參數名不是find系函數已定義的位置參數名,參數會被kwargs收集並被當做標籤的屬性來搜索。
- 屬性的傳參可以是字符串、正則表達式對象、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屬性的節點列表
-
css的class的特殊處理
- 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")) #順序一致,找到。就是字符串完全匹配
- class是Python關鍵字,所以使用
-
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}))))
-
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對象
-
limit參數:顯示返回結果的數量
print(soup.find_all(id=True,limit=3)) #返回列表中有3個結果
-
recursive參數
- 默認是遞歸搜索所有子孫節點,如果不需要請設置爲False
-
簡化寫法
- 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")}))
-
find方法
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"])
CSS選擇器
- 和JQuery一樣,可以使用CSS選擇器來 查找節點
- 使用soup.select()方法,select方法支持大部分CSS選擇器,返回列表。
- CSS中,標籤名直接使用,類名前加
.
點號,id名前加#
井號。
- 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
- 獲取文本內容
- 搜索節點的目的往往是爲了提取該節點的文本內容,一般不需要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,不保留空白字符
- 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] |
切片 |
[] |
?() |
過濾操作 |
不支持 | () |
表達式計算 |
() |
不支持 | 分組 |
- 綜合示例,使用豆瓣電影的熱門電影的Jsonhttps://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&page_limit=10&page_start=0
{
"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])