在上一節中,咱們介紹了Beautiful Soup的用法,它是一個很是強大的網頁解析庫,你是否以爲它的一些方法用起來有點不適應?有沒有以爲它的CSS選擇器的功能沒有那麼強大?css
若是你對Web有所涉及,若是你比較喜歡用CSS選擇器,若是你對jQuery有所瞭解,那麼這裏有一個更適合你的解析庫——pyquery。html
接下來,咱們就來感覺一下pyquery的強大之處。api
在開始以前,請確保已經正確安裝好了pyquery。若沒有安裝,能夠參考第1章的安裝過程。bash
像Beautiful Soup同樣,初始化pyquery的時候,也須要傳入HTML文原本初始化一個PyQuery對象。它的初始化方式有多種,好比直接傳入字符串,傳入URL,傳入文件名,等等。下面咱們來詳細介紹一下。微信
首先,咱們用一個實例來感覺一下:網絡
html = ''' <div> <ul> <li class="item-0">first item</li> <li class="item-1"><a href="link2.html">second item</a></li> <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li> <li class="item-1 active"><a href="link4.html">fourth item</a></li> <li class="item-0"><a href="link5.html">fifth item</a></li> </ul> </div> '''
from pyquery import PyQuery as pq
doc = pq(html)
print(doc('li'))
複製代碼
運行結果以下:app
<li class="item-0">first item</li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
<li class="item-1 active"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a></li>
複製代碼
這裏首先引入PyQuery這個對象,取別名爲pq
。而後聲明瞭一個長HTML字符串,並將其看成參數傳遞給PyQuery
類,這樣就成功完成了初始化。接下來,將初始化的對象傳入CSS選擇器。在這個實例中,咱們傳入li
節點,這樣就能夠選擇全部的li
節點。函數
初始化的參數不只能夠以字符串的形式傳遞,還能夠傳入網頁的URL,此時只須要指定參數爲url
便可:測試
from pyquery import PyQuery as pq
doc = pq(url='http://cuiqingcai.com')
print(doc('title'))
複製代碼
運行結果以下:ui
<title>靜覓丨崔慶才的我的博客</title>
複製代碼
這樣的話,PyQuery
對象會首先請求這個URL,而後用獲得的HTML內容完成初始化,這其實就至關於用網頁的源代碼以字符串的形式傳遞給PyQuery
類來初始化。
它與下面的功能是相同的:
from pyquery import PyQuery as pq
import requests
doc = pq(requests.get('http://cuiqingcai.com').text)
print(doc('title'))
複製代碼
固然,除了傳遞URL,還能夠傳遞本地的文件名,此時將參數指定爲filename
便可:
from pyquery import PyQuery as pq
doc = pq(filename='demo.html')
print(doc('li'))
複製代碼
固然,這裏須要有一個本地HTML文件demo.html,其內容是待解析的HTML字符串。這樣它會首先讀取本地的文件內容,而後用文件內容以字符串的形式傳遞給PyQuery
類來初始化。
以上3種初始化方式都可,固然最經常使用的初始化方式仍是以字符串形式傳遞。
首先,用一個實例來感覺pyquery的CSS選擇器的用法:
html = ''' <div id="container"> <ul class="list"> <li class="item-0">first item</li> <li class="item-1"><a href="link2.html">second item</a></li> <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li> <li class="item-1 active"><a href="link4.html">fourth item</a></li> <li class="item-0"><a href="link5.html">fifth item</a></li> </ul> </div> '''
from pyquery import PyQuery as pq
doc = pq(html)
print(doc('#container .list li'))
print(type(doc('#container .list li')))
複製代碼
運行結果以下:
<li class="item-0">first item</li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
<li class="item-1 active"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a></li>
<class 'pyquery.pyquery.PyQuery'>
複製代碼
這裏咱們初始化PyQuery
對象以後,傳入了一個CSS選擇器#container .list li
,它的意思是先選取id
爲container
的節點,而後再選取其內部的class
爲list
的節點內部的全部li
節點。而後,打印輸出。能夠看到,咱們成功獲取到了符合條件的節點。
最後,將它的類型打印輸出。能夠看到,它的類型依然是PyQuery
類型。
下面咱們介紹一些經常使用的查詢函數,這些函數和jQuery中函數的用法徹底相同。
查找子節點時,須要用到find()
方法,此時傳入的參數是CSS選擇器。這裏仍是之前面的HTML爲例:
from pyquery import PyQuery as pq
doc = pq(html)
items = doc('.list')
print(type(items))
print(items)
lis = items.find('li')
print(type(lis))
print(lis)
複製代碼
運行結果以下:
<class 'pyquery.pyquery.PyQuery'>
<ul class="list">
<li class="item-0">first item</li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
<li class="item-1 active"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a></li>
</ul>
<class 'pyquery.pyquery.PyQuery'>
<li class="item-0">first item</li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
<li class="item-1 active"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a></li>
複製代碼
首先,咱們選取class
爲list
的節點,而後調用了find()
方法,傳入CSS選擇器,選取其內部的li
節點,最後打印輸出。能夠發現,find()
方法會將符合條件的全部節點選擇出來,結果的類型是PyQuery
類型。
其實find()
的查找範圍是節點的全部子孫節點,而若是咱們只想查找子節點,那麼能夠用children()
方法:
lis = items.children()
print(type(lis))
print(lis)
複製代碼
運行結果以下:
<class 'pyquery.pyquery.PyQuery'>
<li class="item-0">first item</li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
<li class="item-1 active"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a></li>
複製代碼
若是要篩選全部子節點中符合條件的節點,好比想篩選出子節點中class
爲active
的節點,能夠向children()
方法傳入CSS選擇器.active
:
lis = items.children('.active')
print(lis)
複製代碼
運行結果以下:
<li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
<li class="item-1 active"><a href="link4.html">fourth item</a></li>
複製代碼
能夠看到,輸出結果已經作了篩選,留下了class
爲active
的節點。
咱們能夠用parent()
方法來獲取某個節點的父節點,示例以下:
html = ''' <div class="wrap"> <div id="container"> <ul class="list"> <li class="item-0">first item</li> <li class="item-1"><a href="link2.html">second item</a></li> <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li> <li class="item-1 active"><a href="link4.html">fourth item</a></li> <li class="item-0"><a href="link5.html">fifth item</a></li> </ul> </div> </div> '''
from pyquery import PyQuery as pq
doc = pq(html)
items = doc('.list')
container = items.parent()
print(type(container))
print(container)
複製代碼
運行結果以下:
<class 'pyquery.pyquery.PyQuery'>
<div id="container">
<ul class="list">
<li class="item-0">first item</li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
<li class="item-1 active"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a></li>
</ul>
</div>
複製代碼
這裏咱們首先用.list
選取class
爲list
的節點,而後調用parent()
方法獲得其父節點,其類型依然是PyQuery
類型。
這裏的父節點是該節點的直接父節點,也就是說,它不會再去查找父節點的父節點,即祖先節點。
可是若是想獲取某個祖先節點,該怎麼辦呢?這時能夠用parents()
方法:
from pyquery import PyQuery as pq
doc = pq(html)
items = doc('.list')
parents = items.parents()
print(type(parents))
print(parents)
複製代碼
運行結果以下:
<class 'pyquery.pyquery.PyQuery'>
<div class="wrap">
<div id="container">
<ul class="list">
<li class="item-0">first item</li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
<li class="item-1 active"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a></li>
</ul>
</div>
</div>
<div id="container">
<ul class="list">
<li class="item-0">first item</li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
<li class="item-1 active"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a></li>
</ul>
</div>
複製代碼
能夠看到,輸出結果有兩個:一個是class
爲wrap
的節點,一個是id
爲container
的節點。也就是說,parents()
方法會返回全部的祖先節點。
若是想要篩選某個祖先節點的話,能夠向parents()
方法傳入CSS選擇器,這樣就會返回祖先節點中符合CSS選擇器的節點:
parent = items.parents('.wrap')
print(parent)
複製代碼
運行結果以下:
<div class="wrap">
<div id="container">
<ul class="list">
<li class="item-0">first item</li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
<li class="item-1 active"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a></li>
</ul>
</div>
</div>
複製代碼
能夠看到,輸出結果少了一個節點,只保留了class
爲wrap
的節點。
前面咱們說明了子節點和父節點的用法,還有一種節點,那就是兄弟節點。若是要獲取兄弟節點,可使用siblings()
方法。這裏仍是以上面的HTML代碼爲例:
from pyquery import PyQuery as pq
doc = pq(html)
li = doc('.list .item-0.active')
print(li.siblings())
複製代碼
這裏首先選擇class
爲list
的節點內部class
爲item-0
和active
的節點,也就是第三個li
節點。那麼,很明顯,它的兄弟節點有4個,那就是第1、2、4、五個li
節點。
運行結果以下:
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-0">first item</li>
<li class="item-1 active"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a></li>
複製代碼
能夠看到,這正是咱們剛纔所說的4個兄弟節點。
若是要篩選某個兄弟節點,咱們依然能夠向siblings
方法傳入CSS選擇器,這樣就會從全部兄弟節點中挑選出符合條件的節點了:
from pyquery import PyQuery as pq
doc = pq(html)
li = doc('.list .item-0.active')
print(li.siblings('.active'))
複製代碼
這裏咱們篩選了class
爲active
的節點,經過剛纔的結果能夠觀察到,class
爲active
的兄弟節點只有第四個li
節點,因此結果應該是一個。
咱們再看一下運行結果:
<li class="item-1 active"><a href="link4.html">fourth item</a></li>
複製代碼
剛纔能夠觀察到,pyquery的選擇結果多是多個節點,也多是單個節點,類型都是PyQuery
類型,並無返回像Beautiful Soup那樣的列表。
對於單個節點來講,能夠直接打印輸出,也能夠直接轉成字符串:
from pyquery import PyQuery as pq
doc = pq(html)
li = doc('.item-0.active')
print(li)
print(str(li))
複製代碼
運行結果以下:
<li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
<li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
複製代碼
對於多個節點的結果,咱們就須要遍從來獲取了。例如,這裏把每個li
節點進行遍歷,須要調用items()
方法:
from pyquery import PyQuery as pq
doc = pq(html)
lis = doc('li').items()
print(type(lis))
for li in lis:
print(li, type(li))
複製代碼
運行結果以下:
<class 'generator'>
<li class="item-0">first item</li>
<class 'pyquery.pyquery.PyQuery'>
<li class="item-1"><a href="link2.html">second item</a></li>
<class 'pyquery.pyquery.PyQuery'>
<li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
<class 'pyquery.pyquery.PyQuery'>
<li class="item-1 active"><a href="link4.html">fourth item</a></li>
<class 'pyquery.pyquery.PyQuery'>
<li class="item-0"><a href="link5.html">fifth item</a></li>
<class 'pyquery.pyquery.PyQuery'>
複製代碼
能夠發現,調用items()
方法後,會獲得一個生成器,遍歷一下,就能夠逐個獲得li
節點對象了,它的類型也是PyQuery
類型。每一個li
節點還能夠調用前面所說的方法進行選擇,好比繼續查詢子節點,尋找某個祖先節點等,很是靈活。
提取到節點以後,咱們的最終目的固然是提取節點所包含的信息了。比較重要的信息有兩類,一是獲取屬性,二是獲取文本,下面分別進行說明。
提取到某個PyQuery
類型的節點後,就能夠調用attr()
方法來獲取屬性:
html = ''' <div class="wrap"> <div id="container"> <ul class="list"> <li class="item-0">first item</li> <li class="item-1"><a href="link2.html">second item</a></li> <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li> <li class="item-1 active"><a href="link4.html">fourth item</a></li> <li class="item-0"><a href="link5.html">fifth item</a></li> </ul> </div> </div> '''
from pyquery import PyQuery as pq
doc = pq(html)
a = doc('.item-0.active a')
print(a, type(a))
print(a.attr('href'))
複製代碼
運行結果以下:
<a href="link3.html"><span class="bold">third item</span></a> <class 'pyquery.pyquery.PyQuery'>
link3.html
複製代碼
這裏首先選中class
爲item-0
和active
的li
節點內的a
節點,它的類型是PyQuery
類型。
而後調用attr()
方法。在這個方法中傳入屬性的名稱,就能夠獲得這個屬性值了。
此外,也能夠經過調用attr
屬性來獲取屬性,用法以下:
print(a.attr.href)
複製代碼
結果以下:
link3.html
複製代碼
這兩種方法的結果徹底同樣。
若是選中的是多個元素,而後調用attr()
方法,會出現怎樣的結果呢?咱們用實例來測試一下:
a = doc('a')
print(a, type(a))
print(a.attr('href'))
print(a.attr.href)
複製代碼
運行結果以下:
<a href="link2.html">second item</a><a href="link3.html"><span class="bold">third item</span></a><a href="link4.html">fourth item</a><a href="link5.html">fifth item</a> <class 'pyquery.pyquery.PyQuery'>
link2.html
link2.html
複製代碼
照理來講,咱們選中的a
節點應該有4個,並且打印結果也應該是4個,可是當咱們調用attr()
方法時,返回結果卻只是第一個。這是由於,當返回結果包含多個節點時,調用attr()
方法,只會獲得第一個節點的屬性。
那麼,遇到這種狀況時,若是想獲取全部的a
節點的屬性,就要用到前面所說的遍歷了:
from pyquery import PyQuery as pq
doc = pq(html)
a = doc('a')
for item in a.items():
print(item.attr('href'))
複製代碼
此時的運行結果以下:
link2.html
link3.html
link4.html
link5.html
複製代碼
所以,在進行屬性獲取時,能夠觀察返回節點是一個仍是多個,若是是多個,則須要遍歷才能依次獲取每一個節點的屬性。
獲取節點以後的另外一個主要操做就是獲取其內部的文本了,此時能夠調用text()
方法來實現:
html = ''' <div class="wrap"> <div id="container"> <ul class="list"> <li class="item-0">first item</li> <li class="item-1"><a href="link2.html">second item</a></li> <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li> <li class="item-1 active"><a href="link4.html">fourth item</a></li> <li class="item-0"><a href="link5.html">fifth item</a></li> </ul> </div> </div> '''
from pyquery import PyQuery as pq
doc = pq(html)
a = doc('.item-0.active a')
print(a)
print(a.text())
複製代碼
運行結果以下:
<a href="link3.html"><span class="bold">third item</span></a>
third item
複製代碼
這裏首先選中一個a
節點,而後調用text()
方法,就能夠獲取其內部的文本信息。此時它會忽略掉節點內部包含的全部HTML,只返回純文字內容。
但若是想要獲取這個節點內部的HTML文本,就要用html()
方法了:
from pyquery import PyQuery as pq
doc = pq(html)
li = doc('.item-0.active')
print(li)
print(li.html())
複製代碼
這裏咱們選中了第三個li
節點,而後調用了html()
方法,它返回的結果應該是li
節點內的全部HTML文本。
運行結果以下:
<a href="link3.html"><span class="bold">third item</span></a>
複製代碼
這裏一樣有一個問題,若是咱們選中的結果是多個節點,text()
或html()
會返回什麼內容?咱們用實例來看一下:
html = ''' <div class="wrap"> <div id="container"> <ul class="list"> <li class="item-1"><a href="link2.html">second item</a></li> <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li> <li class="item-1 active"><a href="link4.html">fourth item</a></li> <li class="item-0"><a href="link5.html">fifth item</a></li> </ul> </div> </div> '''
from pyquery import PyQuery as pq
doc = pq(html)
li = doc('li')
print(li.html())
print(li.text())
print(type(li.text())
複製代碼
運行結果以下:
<a href="link2.html">second item</a>
second item third item fourth item fifth item
<class 'str'>
複製代碼
結果可能比較出乎意料,html()
方法返回的是第一個li
節點的內部HTML文本,而text()
則返回了全部的li
節點內部的純文本,中間用一個空格分割開,即返回結果是一個字符串。
因此這個地方值得注意,若是獲得的結果是多個節點,而且想要獲取每一個節點的內部HTML文本,則須要遍歷每一個節點。而text()
方法不須要遍歷就能夠獲取,它將全部節點取文本以後合併成一個字符串。
pyquery提供了一系列方法來對節點進行動態修改,好比爲某個節點添加一個class
,移除某個節點等,這些操做有時候會爲提取信息帶來極大的便利。
因爲節點操做的方法太多,下面舉幾個典型的例子來講明它的用法。
咱們先用實例來感覺一下:
html = ''' <div class="wrap"> <div id="container"> <ul class="list"> <li class="item-0">first item</li> <li class="item-1"><a href="link2.html">second item</a></li> <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li> <li class="item-1 active"><a href="link4.html">fourth item</a></li> <li class="item-0"><a href="link5.html">fifth item</a></li> </ul> </div> </div> '''
from pyquery import PyQuery as pq
doc = pq(html)
li = doc('.item-0.active')
print(li)
li.removeClass('active')
print(li)
li.addClass('active')
print(li)
複製代碼
首先選中了第三個li
節點,而後調用removeClass()
方法,將li
節點的active
這個class
移除,後來又調用addClass()
方法,將class
添加回來。每執行一次操做,就打印輸出當前li
節點的內容。
運行結果以下:
<li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
<li class="item-0"><a href="link3.html"><span class="bold">third item</span></a></li>
<li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
複製代碼
能夠看到,一共輸出了3次。第二次輸出時,li
節點的active
這個class
被移除了,第三次class
又添加回來了。
因此說,addClass()
和removeClass()
這些方法能夠動態改變節點的class
屬性。
固然,除了操做class
這個屬性外,也能夠用attr()
方法對屬性進行操做。此外,還能夠用text()
和html()
方法來改變節點內部的內容。示例以下:
html = ''' <ul class="list"> <li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li> </ul> '''
from pyquery import PyQuery as pq
doc = pq(html)
li = doc('.item-0.active')
print(li)
li.attr('name', 'link')
print(li)
li.text('changed item')
print(li)
li.html('<span>changed item</span>')
print(li)
複製代碼
這裏咱們首先選中li
節點,而後調用attr()
方法來修改屬性,其中該方法的第一個參數爲屬性名,第二個參數爲屬性值。接着,調用text()
和html()
方法來改變節點內部的內容。三次操做後,分別打印輸出當前的li
節點。
運行結果以下:
<li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li>
<li class="item-0 active" name="link"><a href="link3.html"><span class="bold">third item</span></a></li>
<li class="item-0 active" name="link">changed item</li>
<li class="item-0 active" name="link"><span>changed item</span></li>
複製代碼
能夠發現,調用attr()
方法後,li
節點多了一個本來不存在的屬性name
,其值爲link
。接着調用text()
方法,傳入文本以後,li
節點內部的文本全被改成傳入的字符串文本了。最後,調用html()
方法傳入HTML文本後,li
節點內部又變爲傳入的HTML文本了。
因此說,若是attr()
方法只傳入第一個參數的屬性名,則是獲取這個屬性值;若是傳入第二個參數,能夠用來修改屬性值。text()
和html()
方法若是不傳參數,則是獲取節點內純文本和HTML文本;若是傳入參數,則進行賦值。
顧名思義,remove()
方法就是移除,它有時會爲信息的提取帶來很是大的便利。下面有一段HTML文本:
html = ''' <div class="wrap"> Hello, World <p>This is a paragraph.</p> </div> '''
from pyquery import PyQuery as pq
doc = pq(html)
wrap = doc('.wrap')
print(wrap.text())
複製代碼
如今想提取Hello, World
這個字符串,而不要p
節點內部的字符串,須要怎樣操做呢?
這裏直接先嚐試提取class
爲wrap
的節點的內容,看看是否是咱們想要的。運行結果以下:
Hello, World This is a paragraph.
複製代碼
這個結果還包含了內部的p
節點的內容,也就是說text()
把全部的純文本全提取出來了。若是咱們想去掉p
節點內部的文本,能夠選擇再把p
節點內的文本提取一遍,而後從整個結果中移除這個子串,但這個作法明顯比較煩瑣。
這時remove()
方法就能夠派上用場了,咱們能夠接着這麼作:
wrap.find('p').remove()
print(wrap.text())
複製代碼
首先選中p
節點,而後調用了remove()
方法將其移除,而後這時wrap
內部就只剩下Hello, World
這句話了,而後再利用text()
方法提取便可。
另外,其實還有不少節點操做的方法,好比append()
、empty()
和prepend()
等方法,它們和jQuery的用法徹底一致,詳細的用法能夠參考官方文檔:pyquery.readthedocs.io/en/latest/a…。
CSS選擇器之因此強大,還有一個很重要的緣由,那就是它支持多種多樣的僞類選擇器,例如選擇第一個節點、最後一個節點、奇偶數節點、包含某一文本的節點等。示例以下:
li = doc('li:contains(second)')
print(li)
複製代碼
這裏咱們使用了CSS3的僞類選擇器,依次選擇了第一個li
節點、最後一個li
節點、第二個li
節點、第三個li
以後的li
節點、偶數位置的li
節點、包含second
文本的li
節點。
關於CSS選擇器的更多用法,能夠參考www.w3school.com.cn/css/index.a…。
到此爲止,pyquery的經常使用用法就介紹完了。若是想查看更多的內容,能夠參考pyquery的官方文檔:pyquery.readthedocs.io。咱們相信有了它,解析網頁再也不是難事。
本資源首發於崔慶才的我的博客靜覓: Python3網絡爬蟲開發實戰教程 | 靜覓
如想了解更多爬蟲資訊,請關注個人我的微信公衆號:進擊的Coder
weixin.qq.com/r/5zsjOyvEZ… (二維碼自動識別)