




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
第4章解析網頁數據《Python網絡爬蟲基礎教程》學習目標/Target了解解析網頁的技術,能夠說出正則表達式、Xpath、BeautifulSoup與JSONPath的特點熟悉正則表達式的語法,能夠歸納元字符與預定義字符集的含義掌握re模塊的用法,能夠靈活應用re模塊解析網頁數據了解XPath的概念,能夠說出XPath的路徑表達式的搜索方法學習目標/Target掌握XPath的語法,能夠編寫XPath的路徑表達式掌握XPath的開發(fā)工具,能夠獨立安裝與使用XPathHelper工具掌握lxml庫的用法,能夠靈活應用lxml庫解析網頁數據熟悉BeautifulSoup,能夠歸納BeautifulSoup包含的類的基本用法學習目標/Target掌握BeautifulSoup類對象的創(chuàng)建方式,能夠使用BeautifulSoup類的構造方法創(chuàng)建BeautifulSoup類的對象掌握BeautifulSoup中選取節(jié)點的方式,能夠使用查找方法和CSS選擇器選取節(jié)點熟悉JSONPath的語法,能夠熟練地編寫JSONPath的表達式掌握jsonpath模塊的用法,能夠靈活運用jsonpath模塊解析JSON文檔章節(jié)概述/Summary通過對第3章的學習,我們已經將整個靜態(tài)網頁的源代碼全部抓取下來了,并且源代碼包含了最終要提取的數據。這些數據分為非結構化數據和結構化數據兩種。由于這兩種數據各有各的特點,因此需要采用不同的技術進行解析,提取與目標有關的數據。本章將圍繞著解析網頁數據的相關知識進行詳細講解。目錄/Contents4.14.24.3解析網頁數據的技術正則表達式與re模塊XPath與lxml庫目錄/Contents4.44.54.6BeautifulSoup庫JSONPath與jsonpath模塊實踐項目:采集黑馬程序員論壇的帖子解析網頁數據的技術4.1了解解析網頁的技術,能夠說出正則表達式、Xpath、BeautifulSoup與JSONPath的作用學習目標4.1解析網頁數據的技術Python中提供了多種解析網頁數據的技術,包括正則表達式、XPath、BeautifulSoup、JSONPath。4.1解析網頁數據的技術正則表達式XPathBeautifulSoupJSONPath正則表達式是一種文本模式,這種模式描述了匹配字符串的規(guī)則,用于檢索字符串中是否有符合該模式的子串,或者對匹配到的子串進行替換。正則表達式的優(yōu)點是功能強大,應用廣泛,缺點是只適合匹配文本的字面意義,而不適合匹配文本意義。例如,正則表達式在匹配嵌套了HTML內容的文本時,會忽略HTML內容本身存在的層次結構,而是將HTML內容作為普通文本進行搜索。Python中提供了多種解析網頁數據的技術,包括正則表達式、XPath、BeautifulSoup、JSONPath。4.1解析網頁數據的技術正則表達式XPathBeautifulSoupJSONPathXPath是XML路徑語言,用于從HTML或XML格式的數據中提取所需的數據。XPath適合處理層次結構比較明顯的數據,它能夠基于HTML或XML的節(jié)點樹確定目標節(jié)點所在的路徑,順著這個路徑便可以找到節(jié)點對應的文本或屬性值。Python中提供了多種解析網頁數據的技術,包括正則表達式、XPath、BeautifulSoup、JSONPath。4.1解析網頁數據的技術正則表達式XPathBeautifulSoupJSONPathBeautifulSoup是一個可以從HTML或XML文件中提取數據的Python庫,它同樣可以使用XPath語法提取數據,并且也在此基礎上做了方便開發(fā)者的封裝,提供了更多選取節(jié)點的方式。Python中提供了多種解析網頁數據的技術,包括正則表達式、XPath、BeautifulSoup、JSONPath。正則表達式XPathBeautifulSoupJSONPathJSONPath的作用類似XPath,它也是以表達式的方式解析數據的,但只能解析JSON格式的數據。4.1解析網頁數據的技術若要解析純文本,則可以選擇正則表達式;若要解析HTML或XML格式的數據,則可以選擇正則表達式、XPath、BeautifulSoup;若要解析JSON格式的數據,則可以選擇JSONPath。為便于開發(fā)者使用這些技術,Python提供了一些庫或模塊進行支持,包括re、lxml、bs4、jsonpath,其中re模塊支持正則表達式;lxml庫和bs4庫支持XPath;jsonpath模塊支持JSONPath。4.1解析網頁數據的技術正則表達式與re模塊4.2熟悉正則表達式的語法,能夠歸納元字符與預定義字符集的含義學習目標4.2.1正則表達式的語法正則表達式是對字符串操作的一種邏輯公式,它會將事先定義好的一些特定字符,以及這些特定字符的組合,組成一個規(guī)則字符串,并且通過這個規(guī)則字符串表達對給定字符串的過濾邏輯。一條正則表達式也稱為一個模式,使用每個模式可以匹配指定文本中與表達式模式相同的字符串。正則表達式由普通字符、元字符或預定義字符集組成,其中普通字符包括大小寫字母和數字。4.2.1正則表達式的語法
元字符在正則表達式中,元字符是指具有特殊含義的專用字符,主要用于規(guī)定其前導字符在給定字符串中出現的模式。4.2.1正則表達式的語法元字符說明.匹配任何一個字符(除換行符外)^匹配字符串的開頭$匹配字符串的末尾|連接多個子表達式,匹配與任意子表達式模式相同的字符串[]字符組,匹配其中的出現的任意一個字符-連字符,匹配指定范圍內的任意一個字符?匹配其前導字符0次或1次*匹配其前導字符0次或多次+匹配其前導字符1次或多次{n}匹配其前導字符n次{m,n}匹配其前導字符m~n次()分組,匹配子組
預定義字符集在正則表達式中,除了前面介紹的元字符之外,還預定義了一些字符集,這些字符集以更加簡潔的方式描述了一些由普通字符和元字符組合的模式。4.2.1正則表達式的語法預定義字符集說明\w匹配下畫線“_”或任何字母(a~z,A~Z)與數字(0~9)\s匹配任意的空白字符,等價于[<空格>\t\r\n\f\v]\d匹配任意數字,等價于[0-9]
\b匹配單詞的邊界\W與\w相反,匹配非字母或數字或下畫線的字符\S與\s相反,匹配任意非空白字符的字符,等價于[^\s]\D與\d相反,匹配任意非數字的字符,等價于[^\d]\B與\b相反,匹配不出現在單詞邊界的元素\A僅匹配字符串開頭,等價于^\Z僅匹配字符串結尾,等價于$掌握re模塊的用法,能夠靈活應用re模塊解析網頁數據學習目標4.2.2re模塊的使用4.2.2re模塊的使用Python中提供了re模塊操作正則表達式,該模塊中提供了豐富的函數或方法來實現文本匹配查找、文本替換、文本分割等功能。re模塊的使用一般可以分為兩步,分別是創(chuàng)建Pattern對象和全文匹配。4.2.2re模塊的使用為了節(jié)省每次編譯正則表達式的開銷,保證正則表達式可以重復使用,我們可以使用compile()函數對正則表達式進行預編譯,從而生成一個代表正則表達式的Pattern對象。
創(chuàng)建Pattern對象4.2.2re模塊的使用compile(pattern,flags=0)以上函數中,參數pattern表示一個正則表達式;參數flags用于指定正則表達式匹配的模式,該參數的常用取值及其含義如下。re.I:忽略大小寫。re.L:做本地化識別(locale-aware)匹配,使預定義字符集\w、\W、\b、\B、\s、\S取決于當前區(qū)域設定。re.M:多行匹配,影響“^”和“$”。re.S:使字符“.”匹配所有字符,包括換行符。re.U:根據Unicode字符集匹配字符。re.A:根據ASCII字符集匹配字符。re.X:允許使用更靈活的格式(多行、忽略空白字符、加入注釋)書寫正則表達式。
創(chuàng)建Pattern對象4.2.2re模塊的使用如果希望從全部文本中匹配所有符合正則表達式的字符串,則可以使用Pattern對象的findall()與finditer()函數,其中findall()函數用于獲取目標文本中所有與正則表達式匹配的內容,并將所有匹配的內容以列表的形式返回;finditer()函數同樣可以獲取目標文本中所有與正則表達式匹配的內容,但該方法會將匹配到的子串以迭代器的形式返回。
全文匹配findall(pattern,string,flags=0)findall()函數的聲明如下:4.2.2re模塊的使用
全文匹配pattern:表示一個正則表達式。string:表示待匹配的文本。flags:用于指定正則表達式匹配的模式,該參數支持的取值與compile()函數中參數flags的取值相同。4.2.2re模塊的使用importrestring="狗的英文:dog,貓的英文:cat。"reg_zhn=pile(r"[\u4e00-\u9fa5]+")print(re.findall(reg_zhn,string))以字符串“狗的英文:dog,貓的英文:cat?!睘槔?,使用findall()函數匹配該字符串中所有的中文,示例代碼如下所示:運行代碼,結果如下所示:['狗的英文','貓的英文']
全文匹配XPath與lxml庫4.3正則表達式雖然可以處理包含了諸如HTML或XML內容的字符串,但是它只能根據文本的特征匹配字符串,而忽略了字符串中包含內容的真實格式。為了解決這個問題,Python中引入了XPath以及支持XPath的第三方庫lxml,專門對XML或HTML格式的數據進行解析。4.3XPath與lxml庫了解XPath的概念,能夠說出XPath的路徑表達式的作用學習目標4.3.1XPath簡介XPath即XML路徑語言(全稱XmlPathLanguage),是一種用于確定XML文檔中部分節(jié)點位置的語言,它起初只支持搜索XML文檔,更新后也支持搜索HTML文檔。4.3.1XPath簡介4.3.1XPath簡介XPath是如何搜索XML或HTML文檔?4.3.1XPath簡介其實XPath基于XML或HTML的節(jié)點樹,沿著節(jié)點樹的節(jié)點關系定位到目標節(jié)點所在的位置,并選取節(jié)點或節(jié)點集。為了形象地描述出搜索節(jié)點的路徑,XPath提供了簡潔明了的路徑表達式,通過路徑表達式可以快速地定位與選取XML或HTML文檔中的一個節(jié)點或者一組節(jié)點集。與正則表達式相比路徑表達式有什么區(qū)別?正則表達式路徑表達式與正則表達式相比,路徑表達式的搜索方式大不相同,這里我們借用一個形象的例子進行比較。假如我們把選取目標節(jié)點比作找金燕龍辦公樓,如果我們通過正則表達式查找,則正則表達式會告訴你辦公樓有哪些特征,辦公樓的左邊有哪些建筑,右邊有哪些建筑,這樣的描述限定的查找范圍比較寬泛,查找起來比較繁瑣;如果采用路徑表達式查找,則路徑表達式會直接告訴你辦公樓的具體位置,即中國北京市昌平區(qū)建材城西路金燕龍辦公樓一層,這樣的描述更加精準,更易查找。4.3.1XPath簡介正則表達式路徑表達式路徑表達式描述了從一個節(jié)點到另一個節(jié)點或一組節(jié)點的順序,它與在常規(guī)的計算機文件系統(tǒng)中見到的路徑非常相似。例如,“/學生名單/班級/學生/籍貫”就是一個路徑表達式,該路徑表達式也是用“/”字符進行分隔的,只不過它分隔的是節(jié)點,而不是目錄。4.3.1XPath簡介與正則表達式相比路徑表達式有什么區(qū)別?通過一張示意圖來描述XML文檔、XML節(jié)點樹與路徑表達式的關系。正則表達式路徑表達式4.3.1XPath簡介從左到右依次為XML文檔、XML節(jié)點樹和路徑表達式,其中路徑表達式為“/bookstore/book/price”,它對應的路徑為圖中加粗的線條,用于選取節(jié)點<price>對應的文本39.95。掌握XPath的語法,能夠編寫XPath的路徑表達式學習目標4.3.2XPath語法4.3.2XPath語法如果要編寫一個路徑表達式,則要先了解XPath的語法,如此才能使用路徑表達式正確地選取節(jié)點。路徑表達式會從某個節(jié)點開始沿著節(jié)點樹查找節(jié)點,直至找到目標節(jié)點為止。由于節(jié)點的多樣性,為了幫助開發(fā)人員快速選取目標節(jié)點,XPath提供了一套語法規(guī)則。4.3.2XPath語法下面從選取節(jié)點、謂語、選取未知節(jié)點、選取若干路徑這4個方面介紹XPath的語法。選取節(jié)點謂語選取未知節(jié)點選取若干路徑選取節(jié)點是最基礎的操作,節(jié)點所在的路徑既可以是從根節(jié)點開始的,也可以從任意位置開始的。表達式說明節(jié)點名稱選取此節(jié)點的所有子節(jié)點/從根節(jié)點選取直接子節(jié)點,相當于絕對路徑//從當前節(jié)點選取后代節(jié)點,相當于相對路徑.選取當前節(jié)點..選取當前節(jié)點的父節(jié)點@選取屬性節(jié)點下面以一個XML文檔bookstore.xml為例,演示通過XPath語法選取XML文檔中的節(jié)點。選取節(jié)點的示例4.3.2XPath語法<?xmlversion="1.0"encoding="ISO-8859-1"?><bookstore><book><titlelang="eng">HarryPotter</title><price>29.99</price></book><book><titlelang="eng">LearningXML</title><price>39.95</price></book></bookstore>bookstore#選取bookstore的所有子節(jié)點/bookstore#選取根節(jié)點bookstorebookstore/book#從根節(jié)點bookstore開始,向下選取名為book的所有子節(jié)點//book#從任意節(jié)點開始,選取名為book的所有子節(jié)點bookstore//book#從bookstore的后代節(jié)點中,選取名為book的所有子節(jié)點//@lang#選取所有名為lang的屬性節(jié)點4.3.2XPath語法選取節(jié)點謂語選取未知節(jié)點選取若干路徑謂語是為路徑表達式附加的條件,主要用于篩選當前被處理的節(jié)點集,選取出滿足某個特定的節(jié)點,或者包含了指定屬性或基本值的節(jié)點。謂語會嵌入到方括號中,位于要補充說明的節(jié)點后面。節(jié)點[謂語]方括號中的謂語可以是整數、屬性、函數,也可以是整數、屬性、函數與運算符組合的表達式。如果謂語是整數(從1開始),則這個數值將作為位置,用于從節(jié)點集中選取與該位置對應的節(jié)點;如果為屬性,則會從節(jié)點集中選取包含該屬性的節(jié)點;如果為函數,則會將該函數的返回值作為條件,從節(jié)點集中選取滿足條件的節(jié)點。4.3.2XPath語法常用的XPath函數如下表所示。函數說明position()返回當前被處理的節(jié)點的位置last()返回當前節(jié)點集中的最后一個節(jié)點count()返回節(jié)點的總數目max((arg,arg,...))返回大于其他參數的參數min((arg,arg,...))返回小于其他參數的參數name()返回當前節(jié)點的名稱current-date()返回當前的日期(帶有時區(qū))current-time()返回當前的時間(帶有時區(qū))contains(string1,string2)若string1包含string2,則返回true,否則返回false選取節(jié)點謂語選取未知節(jié)點選取若干路徑以前面的bookstore.xml為例,演示帶謂語的路徑表達式的用法,具體代碼如下所示。4.3.2XPath語法/bookstore/book[1]#選取屬于bookstore子節(jié)點的第1個book節(jié)點/bookstore/book[last()]#選取屬于bookstore子節(jié)點的最后一個book節(jié)點/bookstore/book[last()-1]#選取屬于bookstore子節(jié)點的倒數第2個book節(jié)點/bookstore/book[position()<3]#選取屬于bookstore子節(jié)點的前兩個book節(jié)點//title[@lang]#選取所有的屬性名稱為lang的title節(jié)點//title[@lang='eng']#選取所有的屬性名稱為lang且屬性值為eng的title節(jié)點#選取子節(jié)點price的值大于35.00,且父節(jié)點為bookstore的所有book節(jié)點/bookstore/book[price>35.00]#選取屬于book的所有子節(jié)點title,且節(jié)點book的子節(jié)點price的值必須大于35.00/bookstore/book[price>35.00]/title4.3.2XPath語法選取節(jié)點謂語選取未知節(jié)點選取若干路徑XPath中提供了選取未知節(jié)點的通配符和函數。/bookstore/*#選取屬于bookstore的所有子節(jié)點//*#選取文檔中的所有節(jié)點//title[@*]#選取所有帶有屬性的節(jié)點title通配符/函數說明*匹配任何元素節(jié)點@*匹配任何屬性節(jié)點node()匹配任何類型的節(jié)點以bookstore.xml為例,演示通配符或函數的用法。4.3.2XPath語法選取節(jié)點謂語選取未知節(jié)點選取若干路徑在XPath中,我們可以使用“|”運算符連接多個路徑表達式,以根據多個路徑選取對應的節(jié)點。以bookstore.xml為例,演示“|”的用法。//book/title|//book/price#選取屬于book的子節(jié)點title和price//title|//price#選取所有的title和price節(jié)點#選取屬于/bookstore/book/的所有title節(jié)點,以及文檔中所有的節(jié)點price/bookstore/book/title|//price掌握XPath的開發(fā)工具,能夠獨立安裝與使用XPathHelper工具學習目標4.3.3XPath開發(fā)工具XPathHelper是一款運行在Chrome瀏覽器的插件,它支持在網頁上單擊元素生成路徑表達式,也支持對照網頁源代碼手動編寫路徑表達式。在使用XPathHelper測試之前,我們需要先在Chrome瀏覽器上添加XPathHelper插件。4.3.3XPath開發(fā)工具4.3.3XPath開發(fā)工具步驟1步驟2步驟3安裝XPathHelper插件在Chrome瀏覽器的右上角單擊按鈕打開自定義及控制GoogleChrome菜單,在該菜單中單擊“更多工具”→“擴展程序”進入擴展程序頁面。4.3.3XPath開發(fā)工具步驟2步驟1步驟3安裝XPathHelper插件將XPathHelper.crx文件拖入到擴展程序頁面中,可以看到該頁面中增加了擴展程序XPathHelper,打開該擴展程序對應的開啟按鈕,此時擴展程序頁面的右上角位置顯示了XPathHelper的圖標
。4.3.3XPath開發(fā)工具步驟3步驟1步驟2安裝XPathHelper插件單擊圖標可以看到瀏覽器頂部彈出一個XPathHelper界面。界面左側的編輯區(qū)域用于輸入路徑表達式,右側區(qū)域用于展示通過該路徑表達式選取的結果,并且會將結果總數目(默認顯示的值為0)顯示到RESULTS后面的括號里面。4.3.3XPath開發(fā)工具步驟1步驟2步驟3使用XPathHelper插件在瀏覽器中打開豆瓣電影首頁,在該頁面中單擊“排行榜”→“喜劇”進入喜劇電影排行榜首頁。喜劇電影排行榜首頁中默認展示20部電影,當滾動條滑至頁面底部時,會有新的電影加載到頁面中。在該頁面頂部第一部電影名稱“美麗人生”的上方單擊鼠標右鍵,打開快捷菜單,在該菜單中選擇“檢查”。頁面底部彈出了帶Elements的界面,并定位到了電影名稱“美麗人生”對應元素源代碼的位置。4.3.3XPath開發(fā)工具步驟2步驟1步驟3安裝XPathHelper插件分析上頁圖中元素的層次結構后,推斷出最終的路徑表達式可以為://div[@class='movie-info']/div/span/a/text()需要說明的是,路徑表達式并不是唯一的,既可以是從根節(jié)點開始的絕對路徑,也可以是從任意節(jié)點開始的相對路徑。4.3.3XPath開發(fā)工具步驟3步驟1步驟2安裝XPathHelper插件打開XPathHelper工具,在左側的編輯區(qū)域中輸入上述路徑表達式,此時右側區(qū)域中展示了選取的結果及數目。掌握lxml庫的用法,能夠靈活應用lxml庫解析網頁數據學習目標4.3.4lxml庫簡介4.3.4lxml庫簡介在lxml庫中,大多數有關解析的功能都封裝到
etree模塊中,etree模塊中包含了兩個比較重要的類,分別是ElementTree類和Element類。ElementTree類的對象可以理解為一個HTML或XML文檔的節(jié)點樹。為方便開發(fā)者將HTML或XML文檔轉換為ElementTree類的對象,etree模塊中提供了一個parse()函數。parse(source,parser=None,base_url=None)
ElementTree類4.3.4lxml庫簡介source:必選參數,表示待解析的內容,該參數共支持4種類型的取值,分別是打開的文件對象(確保以二進制模式打開)、類似文件的對象、字符串形式的文件名稱、字符串形式的URL。parser:可選參數,表示解析器。若未指定解析器,則會使用默認的解析器;若希望指定其他的解析器,則可以通過help(etree.XMLParser)查看lxml支持的解析器。base_url:可選參數,表示基礎URL。以bookstore.xml為例,演示如何根據該文檔使用parse()函數創(chuàng)建ElementTree類的對象。fromlxmlimportetree#從bookstore.xml文件中解析,返回ElementTree類的對象ele_tree=etree.parse(r'bookstore.xml')print(type(ele_tree))
ElementTree類4.3.4lxml庫簡介運行代碼,結果如下所示。<class'lxml.etree._ElementTree'>
ElementTree類4.3.4lxml庫簡介etree模塊中還提供了3個函數:fromstring()、XML()和HTML(),這3個函數也可以解析HTML或XML文檔或片段,只不過在解析成功后返回根節(jié)點或者解析器目標返回的結果。其中,fromstring()函數和XML()函數的功能相同,都可以從字符串常量中解析XML文檔或片段;HTML()函數用于從字符串常量中解析HTML文檔或片段,并能夠自動補全文檔或片段中缺少的<html>和<body>元素。Element類的對象可以理解為XML或HTML文檔的節(jié)點,它與Python中的列表非常相似,可以使用諸如len()、append()、remove()等方法修改節(jié)點,也可以使用索引、切片獲取節(jié)點集中的子節(jié)點。print(root_node[:])
#獲取所有的子節(jié)點print(root_node[0])
#獲取第1個子節(jié)點print(root_node[1])
#獲取第2個子節(jié)點
Element類4.3.4lxml庫簡介使用索引或切片獲取root_node對象中的子節(jié)點,具體代碼如下所示。運行代碼,結果如下所示:[<Elementbookat0x34cae00>,<Elementbookat0x34cae80>]<Elementbookat0x34cae00><Elementbookat0x34cae00>Element類還提供了一些獲取節(jié)點的屬性,關于這些屬性及其說明如下表。
Element類4.3.4lxml庫簡介屬性說明tag獲取節(jié)點的名稱text獲取第一個子元素之前的文本。若沒有文本,則獲得的結果可以是字符串或Nonetail獲取當前元素的結束標記之后,下一個同級元素的開始標記之前的文本。若沒有文本,則獲得的結果可以是字符串或Noneattrib獲取屬性節(jié)點的字典ElementTree類或Element類中提供了3個常用的查找方法,分別是find()、findall()、xpath(),這3個方法都會從節(jié)點樹的根節(jié)點開始查找目標節(jié)點。
ElementTree類或Element類的查找方法4.3.4lxml庫簡介find()方法:從節(jié)點樹的某個節(jié)點開始查找,返回匹配到的第一個子節(jié)點。findall()方法:從節(jié)點樹的某個節(jié)點開始查找,以列表的形式返回匹配到的所有子節(jié)點。xpath()方法:從節(jié)點樹的根節(jié)點或某個節(jié)點開始查找,以列表的形式返回匹配到的所有子節(jié)點。以上3個方法都可以接收XPath的路徑表達式,并在調用成功后返回查找到的最終結果,不過find()和findall()方法只支持相對路徑,xpath()方法支持相對路徑和絕對路徑。需要注意的是,若find()方法未找到匹配項,則會返回None;若findall()和xpath()方法未找到匹配項,則會返回一個空列表。以root_node對象為例,分別使用以上3個方法的查找第一個price節(jié)點的文本,示例代碼如下所示。
ElementTree類或Element類的查找方法4.3.4lxml庫簡介res1=root_node.find('.//price').textprint(res1)res2=root_node.findall('.//price')[0].textprint(res2)res3=root_node.xpath('.//price')[0].textprint(res3)BeautifulSoup4.44.4BeautifulSoup在使用lxml庫解析網頁數據時,每次都需要編寫和測試XPath的路徑表達式,顯得非常煩瑣。為了解決這個問題,Python還提供了BeautifulSoup提取HTML或XML文檔的節(jié)點,BeautifulSoup使用起來更加便捷,受到了開發(fā)人員的推崇。熟悉BeautifulSoup,能夠歸納BeautifulSoup常用類的使用學習目標4.4.1BeautifulSoup簡介BeautifulSoup是一個用于從HTML或XML文檔中提取目標數據的Python庫,它歷經了眾多版本,其中BeautifulSoup3目前已經停止開發(fā)與維護,官方推薦使用BeautifulSoup4(簡稱為bs4)進行開發(fā)。4.4.1BeautifulSoup簡介為了快速解析HTML或XML文檔的數據,bs4不僅提供了多種解析器,還支持CSS選擇器。bs4可以將HTML或XML文檔、片段轉換成節(jié)點樹,并會將整個節(jié)點樹中的每個節(jié)點看作一個Python類的對象。bs4庫或bs4.element模塊中提供了4個比較重要的類,分別是Tag類、NavigableString類、BeautifulSoup類和Comment類。4.4.1BeautifulSoup簡介bs4.element.Tag類:表示HTML中的標簽,是最基本的信息組織單元。它有兩個非常重要的屬性:表示標簽名字的name,表示標簽屬性的attrs。bs4.element.NavigableString類:表示HTML中標簽的文本(非屬性字符串)。bs4.BeautifulSoup類:表示HTML或XML節(jié)點樹中的全部內容,支持遍歷節(jié)點樹和索文檔樹的大部分方法。bs4.element.Comment類:表示元素內字符串的注釋部分,是一種特殊的NavigableString類的對象。4.4.1BeautifulSoup簡介創(chuàng)建Beautiful類的對象定位節(jié)點提取節(jié)點123根據HTML或XML文檔或片段創(chuàng)建一個BeautifulSoup類的對象。通過BeautifulSoup類的對象的查詢方法或CSS選擇器定位節(jié)點。通過訪問節(jié)點的屬性或節(jié)點的名稱提取文本。BeautifulSoup的用法非常簡單,一般分為如下3個步驟。掌握BeautifulSoup類對象的創(chuàng)建方式,能夠使用BeautifulSoup類的構造方法創(chuàng)建BeautifulSoup類對象
學習目標4.4.2創(chuàng)建BeautifulSoup類的對象4.4.2創(chuàng)建BeautifulSoup類的對象要想使用BeautifulSoup解析網頁,需要先使用構造方法創(chuàng)建一個BeautifulSoup類的對象。BeautifulSoup(markup="",features=None,builder=None,parse_only=None,from_encoding=None,exclude_encodings=None,element_classes=None,**kwargs)markup:必選參數,表示待解析的內容,可以取值為字符串或類似文件的對象。features:可選參數,表示指定的解析器。該參數可以接收解析器名稱或標記類型,其中解析器名稱包括lxml、lxml-xml、html.parser和html5lib,標記類型包括"html"、"html5"和"xml"。parse_only:可選參數,用于指定只解析部分文檔,該參數需要接收一個SoupStrainer類的對象。from_encoding:可選參數,用于指定待解析文檔的編碼格式。4.4.2創(chuàng)建BeautifulSoup類的對象值得一提的是,如果我們只需要解析HTML文檔,那么在創(chuàng)建BeautifulSoup類的對象時可以不用指定解析器,此時BeautifulSoup會根據當前系統(tǒng)已經安裝的庫自動選擇解析器,選擇順序為lxml→html5lib→Python標準庫。4.4.2創(chuàng)建BeautifulSoup類的對象如果指定的解析器沒有安裝,那么BeautifulSoup會自動選擇其它方案。不過,目前只有解析器lxml支持XML文檔的解析,在當前系統(tǒng)中沒有安裝解析器lxml的情況下,即便創(chuàng)建beautifulsoup對象時明確指定了使用解析器lxml,也無法得到解析后的對象。解析器優(yōu)勢劣勢lxml(lxml的HTML解析器)(1)執(zhí)行速度快(2)文檔容錯能力強需要安裝C語言庫lxml-xml(lxml的XML解析器)(1)執(zhí)行速度快(2)唯一適用于XML文檔的解析器需要安裝C語言庫html.parser(bs4的HTML解析器)(1)Python內置的標準庫(2)執(zhí)行速度適中(3)文檔容錯能力強Python2.7.3或3.2.2之前的版本中文檔容錯能力差html5lib(1)擁有4中解析器中最好的容錯能力(2)以瀏覽器的方式解析文檔(3)生成HTML5格式的文檔(1)執(zhí)行速度慢(2)不依賴外部擴展1frombs4importBeautifulSoup2html_doc="""<html><head><title>TheDormouse'sstory</title></head>3<body>4<pclass="title"><b>TheDormouse'sstory</b></p>5<pclass="story">Onceuponatimetherewerethreelittlesisters;6andtheirnameswere7<ahref="/elsie"class="sister"id="link1">Elsie</a>,8<ahref="/lacie"class="sister"id="link2">Lacie</a>and9<ahref="/tillie"class="sister"id="link3">Tillie</a>;10andtheylivedatthebottomofawell.</p>11<pclass="story">...</p>12"""13#根據html_doc創(chuàng)建BeautifulSoup類的對象,并指定使用lxml解析器解析文檔14soup=BeautifulSoup(html_doc,features='lxml')15print(soup.prettify())通過一個示例來演示如何創(chuàng)建BeautifulSoup類的對象,具體代碼如下所示。4.4.2創(chuàng)建BeautifulSoup類的對象<html><head><title>TheDormouse'sstory</title></head><body><pclass="title"><b>TheDormouse'sstory</b></p>……</body></html>在上頁示例代碼中,第1行代碼導入了BeautifulSoup類,第2~12行定義了變量html_doc保存HTML代碼片段,第14行代碼根據html_doc創(chuàng)建了BeautifulSoup類的一個對象,并指定使用解析器lxml來解析HTML文檔,第15行代碼輸出了soup.prettify()執(zhí)行的結果,其中prettify()方法會對HTML代碼片段進行格式化處理,友好地顯示HTML代碼。4.4.2創(chuàng)建BeautifulSoup類的對象掌握BeautifulSoup中選取節(jié)點的方式,能夠使用查找方法選取節(jié)點學習目標4.4.3通過查找方法選取節(jié)點find_all(self,name=None,attrs={},recursive=True,text=None,limit=None,**kwargs)BeautifulSoup類中提供了一些基于HTML或XML節(jié)點樹選取節(jié)點的方法,比較主流的兩個方法分別是find()和find_all(),find()方法用于查找符合條件的第一個節(jié)點;find_all()方法用于查找所有符合條件的節(jié)點,并以列表的形式進行返回。4.4.3通過查找方法選取節(jié)點以上方法中包含了多個參數,每個參數接收的值類型不同,查找到的結果也會有所不同。若值為字符串,則會查找名稱與字符串完全相同的所有節(jié)點。例如,使用創(chuàng)建的soup對象調用find_all()方法查找名稱為title的節(jié)點,代碼如下所示。
參數name查找結果如下所示:[<title>TheDormouse'sstory</title>]4.4.3通過查找方法選取節(jié)點soup.find_all('title')若值為正則表達式,則會查找名稱符合正則表達式模式的所有節(jié)點。例如,使用soup對象調用find_all()方法查找id屬性值中含有l(wèi)ink1關鍵字的所有節(jié)點,代碼如下所示。
參數name查找結果如下所示:4.4.3通過查找方法選取節(jié)點soup.find_all(id=pile("link1"))[<aclass="sister"href="/elsie"id="link1">Elsie</a>]若值為列表,則會查找名稱與列表中任一元素相同的所有節(jié)點。例如,使用soup對象調用find_all()方法查找所有名稱為title或a的節(jié)點,代碼如下。
參數name查找結果如下所示:4.4.3通過查找方法選取節(jié)點soup.find_all(["title","a"])[<title>TheDormouse'sstory</title>,<aclass="sister"href="/elsie"id="link1">Elsie</a>,<aclass="sister"href="/lacie"id="link2">Lacie</a>,<aclass="sister"href="/tillie"id="link3">Tillie</a>]參數attrs表示待查找的屬性節(jié)點,它接收一個字典,字典中的鍵為屬性名稱,值為該屬性對應的值。例如,使用soup對象調用find_all()方法查找屬性名稱為id、值為link1的節(jié)點,代碼如下。
參數attrs查找結果如下所示:4.4.3通過查找方法選取節(jié)點soup.find_all(attrs={'id':'link1'})[<aclass="sister"href="/elsie"id="link1">Elsie</a>]參數recursive表示是否對當前節(jié)點的所有子孫節(jié)點進行查找,其默認值為True。如果我們只需要對當前節(jié)點的直接子節(jié)點進行查找,則可以將參數recursive的值設為False。例如,使用soup對象調用find_all()方法查找直接子節(jié)點<head>,代碼如下所示。
參數recursive查找結果如下所示:4.4.3通過查找方法選取節(jié)點soup.html.find_all("head",recursive=False)[<head><title>TheDormouse'sstory</title></head>]參數text表示待查找的文本節(jié)點,它也支持字符串、正則表達式、列表3種類型的取值,具有與name參數的用法相同。例如,使用soup對象調用find_all()方法查找所有文本為Elsie的節(jié)點,代碼如下所示。
參數text查找結果如下所示:4.4.3通過查找方法選取節(jié)點soup.find_all(text="Elsie")['Elsie']參數limit表示待查找的節(jié)點數量。當在節(jié)點樹中尋找節(jié)點時,如果節(jié)點樹非常大,那么查找的速度會非常慢。此時若不需要選取所有符合要求的結果,可以給limit參數指定值以限制結果的數量,一旦數量超過了limit參數的值,就會停止查找。參數limit與SQL語句中l(wèi)imit語句達到的效果類似,都可以限制查找結果的最大數量。例如,使用soup對象調用find_all()方法查找至多1個節(jié)點<a>,代碼如下所示。
參數limit查找結果如下所示:4.4.3通過查找方法選取節(jié)點soup.find_all("a",limit=1)[<aclass="sister"href="/elsie"id="link1">Elsie</a>]參數**kwargs支持以關鍵字形式傳遞的任意個參數。在節(jié)點樹中尋找節(jié)點時,會將關鍵字參數的名稱作為節(jié)點的屬性名稱,值作為屬性值。例如,使用soup對象調用find_all()方法查找屬性名稱為id、值為link3的節(jié)點,代碼如下所示。
參數**kwargs查找結果如下所示:4.4.3通過查找方法選取節(jié)點soup.find_all(id='link3')[<aclass="sister"href="/tillie"id="link3">Tillie</a>]如果我們要查找的節(jié)點名稱為class,由于class屬于Python中的關鍵字,所以需要在class的后面加上一個下畫線,示例代碼如下所示。
參數**kwargs查找結果如下所示:4.4.3通過查找方法選取節(jié)點soup.find_all("p",class_="title")[<pclass="title"><b>TheDormouse'sstory</b></p>]掌握BeautifulSoup中選取節(jié)點的方式,能夠使用CSS選擇器選取節(jié)點學習目標4.4.4通過CSS選擇器選取節(jié)點CSS選擇器,又稱CSS屬性選擇器,它是選擇需設置樣式的元素的模式,這種模式指定了樣式作用于網頁頁面中的哪些元素,可以使用CSS對HTML頁面中的元素進行一對一、一對多或多對一的控制。CSS選擇器有許多種類,其中常用的CSS選擇器有類別選擇器、元素選擇器、ID選擇器和屬性選擇器,關于這4種選擇器的介紹如下。4.4.4通過CSS選擇器選取節(jié)點類別選擇器:根據類名選擇元素,類名前面用“.”進行標注。例如,.intro表示選擇包含class="intro"的所有元素。元素選擇器:根據元素名稱選擇元素。例如,p表示選擇所有<p>元素ID選擇器:根據特定ID選擇元素,ID前面加上“#”進行標注。例如,#link1表示選擇特定ID的值為link1的元素。屬性選擇器:根據元素的屬性選擇元素,屬性必須用中括號進行包裹,它既可以是標準屬性,也可以是自定義屬性。例如,[target=_blank]表示選擇包含target="_blank"的所有元素。除此之外,這些選擇器還可以組合使用,它們之間一般以空格進行分隔。不過,對于元素選擇器和屬性選擇器來說,如果這兩個選擇器屬于同一節(jié)點,那么兩者在組合使用時不需要加空格。例如,a[href="/elsie"]。4.4.4通過CSS選擇器選取節(jié)點select(self,selector,namespaces=None,limit=None,**kwargs)為方便開發(fā)者在bs4庫中使用CSS選擇器,bs4庫的BeautifulSoup類中提供了一個select()方法,該方法會根據CSS選擇器指定的模式選擇目標節(jié)點,并將選到的節(jié)點存放到列表中。select()方法中的selector參數表示CSS選擇器,支持字符串類型的值。4.4.4通過CSS選擇器選取節(jié)點調用select()方法時可以傳入一個類別選擇器,通過指定的類名查找目標節(jié)點。例如,使用soup對象調用select()方法查找類名稱為sister的所有元素,代碼如下。
通過類別選擇器查找元素查找結果如下所示:soup.select('.sister')[<aclass="sister"href="/elsie"id="link1">Elsie</a>,<aclass="sister"href="/lacie"id="link2">Lacie</a>,<aclass="sister"href="/tillie"id="link3">Tillie</a>]4.4.4通過CSS選擇器選取節(jié)點調用select()方法時可以傳入一個元素選擇器,通過元素的名稱查找目標元素。例如,使用soup對象調用select()方法查找所有名稱為title的元素,代碼如下。
通過元素選擇器查找元素查找結果如下所示:soup.select("title")[<title>TheDormouse'sstory</title>]4.4.4通過CSS選擇器選取節(jié)點調用select()方法時可以傳入一個ID選擇器,通過特定的ID名稱查找目標元素。例如,使用soup對象調用select()方法查找ID名稱為link1的元素,代碼如下。
通過ID選擇器查找元素soup.select("#link1")[<aclass="sister"href="/elsie"id="link1">Elsie</a>]4.4.4通過CSS選擇器選取節(jié)點查找結果如下所示:調用select()方法時可以傳入一個屬性選擇器,通過指定的屬性查找目標元素。例如,使用soup對象調用select()方法查找屬性名稱為href、值為"/elsie"的元素,代碼如下所示。
通過屬性選擇器查找元素查找結果如下所示:soup.select('[href="/elsie"]')[<aclass="sister"href="/elsie"id="link1">Elsie</a>]4.4.4通過CSS選擇器選取節(jié)點調用select()方法時可以傳入組合的多個選擇器,通過指定的類名、元素名稱、ID或屬性查找目標元素。例如,使用soup對象調用select()方法查找ID值為"link1"元素<a>,代碼如下所示。
通過組合的多個選擇器查找元素查找結果如下所示:soup.select('a#link1')[<aclass="sister"href="/elsie"id="link1">Elsie</a>]4.4.4通過CSS選擇器選取節(jié)點此時可以遍歷上面的列表,并調用get_text()方法獲取元素的文本,代碼如下所示。forelementinsoup.select('a[href="/elsie"]'):print(element.get_text())#獲取節(jié)點的內容輸出ElsieJsonPath與jsonpath模塊4.54.5JSONPath與jsonpath模塊除HTML和XML外,網頁的數據格式還有JSON。JSON是一種被廣泛使用的結構化數據的格式,它具有清晰的層次結構,可以采用類似JSONPath表達式的方式定位目標對象。Python中提供了支持JSONPath的模塊jsonpath。熟悉JSONPath的語法,能夠熟練地編寫JSONPath的表達式學習目標4.5.1JSONPath語法4.5.1JSONPath語法JSONPath可以看作定位目標對象位置的語言,適用于JSON文檔。JSONPath與JSON關系相當于XPath與XML關系,JSONPath參照XPath的路徑表達式,通過表達式度目標對象定位。JSONPath遵循相對簡單的語法,采用了更加友好的表達式形式JSONPathXPath說明$/選取根對象/根節(jié)點@.選取當前對象/當前節(jié)點.或[]/選取下級對象/子節(jié)點不支持..選取父節(jié)點,JSONPath不支持..//選取所有符合條件的對象/節(jié)點**選取所有對象/節(jié)點不支持@選取屬性節(jié)點,由于JSON沒有屬性,所以JSONPath不支持[][]下標運算符[,]|聯合運算符?()[]支持過濾操作()不支持支持表達式計算不支持()支持分組,JSONPath不支持4.5.1JSONPath語法以一個JSON文檔為例,為大家演示使用JSONPath語法選取JSON文檔的對象。JSON文檔的具體內容如下。{"store":{"book":[{"category":"reference","author":"NigelRees","title":"SayingsoftheCentury","price":8.95},{"category":"fiction","author":"J.R.R.Tolkien","title":"TheLordoftheRings","isbn":"0-394-19394-8","price":22.99}],"bicycle":{"color":"red","price":19.95}}}4.5.1JSONPath語法通過JSONPath的表達式選取節(jié)點的示例代碼如下所示。#選取bicycle對象中字段color的值$.store.bicycle.color#選取books列表中包含的所有對象$.store.book[*]#選取books列表的第一個對象$.store.book[0]#選取books列表中所有對象對應的字段title的值$.store.book[*].title#選取books列表中字段category的值為fiction的所有對象$.store.book[?(@.category=='fiction')]#選取books列表中所有price小于10的對象$.store.book[?(@.price<10)]#選取books列表中所有含有isb的對象$.store.book[?(@.isb)]掌握jsonpath模塊的用法,能夠靈活運用jsonpath模塊解析JSON文檔學習目標4.5.2jsonpath模塊的使用jsonpath是一個解析JSON文檔的模塊,它可以通過JSONPath的表達式從JSON文檔中提取需要的數據。jsonpath支持多種語言的實現版本,包括Python、JavaScript、PHP和Java。值得一提的是,我們需要使用pip工具在本機環(huán)境中安裝jsonpath,具體的安裝命令為“pipinstalljsonpath”,安裝完成后便可以使用jsonpath解析JSON文檔。4.5.2jsonpath模塊的使用jsonpath模塊中提供了一個重要的函數jsonpath()。jsonpath()函數會根據JSONPath的表達式定位目標對象,并從目標對象中提取想要的數據。4.5.2jsonpath模塊的使用jsonpath(obj,expr,result_type='VALUE',debug=0,use_eval=True)obj:必選參數,表示需要解析的對象,該參數支持的取值為Python對象。expr:必選參數,表示JSONPath表達式的字符串。result_type:可選參數,表示結果是匹配值或表達式,該參數支持兩種取值"VALUE"|"PATH"。jsonpath()函數會返回包含解析后的結果的列表。為了幫助大家更好地理解,接下來,以4.5.1節(jié)的JSON文檔為例,使用jsonpath()函數根據表達式選取目標對象。假設變量book_json中保存了4.5.1小節(jié)的JSON文檔,需要將book_json轉換為Python對象,示例代碼如下。4.5.2jsonpath模塊的使用importjsonimportjsonpathbook_json="""JSON文檔字符串"""books=json.loads(book_json)上述示例中,loads()函數是json模塊的函數,用于將JSON格式的字符串轉換為Python對象。經過上述操作后,變量books已經保存了JSON字符串轉換后的Python對象。選取bicycle對象中字段color的值,示例代碼如下。4.5.2jsonpath模塊的使用json_expression="$.store.bicycle.color"result=jsonpath.jsonpath(books,json_expression)print(result)運行代碼,結果如下所示。['red']選取books列表中包含的所有對象,示例代碼如下。4.5.2jsonpath模塊的使用json_expression="$.store.book[*]"result=jsonpath.jsonpath(books,json_expression)print(result)運行代碼,結果如下所示。[{'category':'reference','author':'NigelRees','title':'SayingsoftheCentury','price':8.95},{'category':'fiction','author':'J.R.R.Tolkien','title':'TheLordoftheRings','isbn':'0-394-19394-8','price':22.99}]選取books列表的第一個對象,示例代碼如下。4.5.2jsonpath模塊的使用json_expression="$.store.book[0]"result=jsonpath.jsonpath(books,json_expression)print(result)運行代碼,結果如下所示。[{'category':'reference','author':'NigelRees','title':'SayingsoftheCentury','price':8.95}]選取books列表中所有對象的屬性title的值,示例代碼如下。4.5.2jsonpath模塊的使用json_expression="$.store.book[*].title"result=jsonpath.jsonpath(books,json_expression)print(result)運行代碼,結果如下所示。['SayingsoftheCentury','TheLordoftheRings']選取books列表中屬性category的值為fiction的所有對象,示例代碼如下。4.5.2jsonpath模塊的使用json_expression="$.store.book[?(@.category=='fiction')]"result=jsonpath.jsonpath(books,json_expression)print(result)運行代碼,結果如下所示。[{'category':'fiction','author':'J.R.R.Tolkien','title':'TheLordoftheRings','isbn':'0-394-19394-8','price':22.99}]選取books列表中所有price的值小于10的對象,示例代碼如下。4.5.2jsonpath模塊的使用json_expression="$.store.book[?(@.price<10)]"result=jsonpath.jsonpath(books,json_expression)print(result)運行代碼,結果如下所示。[{'category':'reference','author':'NigelRees','title':'SayingsoftheCentury','price':8.95}]選取books列表中所有包含isbn的對象,示例代碼如下所示。4.5.2jsonpath模塊的使用json_expression="$.store.book[?(@.isbn)]"result=jsonpath.jsonpath(books,json_expression)print(result)運行代碼,結果如下所示。[{'category':'fiction','author':'J.R.R.Tolkien','title':'TheLordoftheRings','isbn':'0-394-19394-8','price':22.99}]多學一招json模塊可以輕松地將Python對象編碼轉換為JSON格式的數據,也可以將JSON格式的數據解碼轉換為Python對象,前者對應的操作過程稱為序列化,后者對應的操作過程稱為反序列化。json模塊json模塊中主要提供了4個函數,分別是loads()、load()、dumps()和dump(),其中l(wèi)oads()和load()函數用于實現反序列化的功能,dumps()和dump()函數用于實現序列化的功能。多學一招l(wèi)oads()和load()函數都可以將JSON格式的數據轉換為Python對象,JSON數據類型向Python對象類型轉換的對照表如下所示。json模塊JSON數據類型說明Python對象類型說明object對象dict字典array數組list列表string字符串str字符串number(int)數字型int整型number(real)數字型float浮點型true布爾型True布爾型false布爾型False布爾型null空None空多學一招l(wèi)oads()和load()函數作用相同,都可以實現反序列化操作,但兩者的用法有著一些區(qū)別,loads()函數需要接收字符串形式的JSON數據,而load()函數需要接收文件形式的JSON數據。json模塊importjson#將JSON對象轉換為Python字典result_dict=json.loads('{"city":"北京","name":"小明"}')print(result_dict)result_dict=json.load(open("dict_str.json"))print(result_dict)多學一招dumps()和dump()函數都可以將Python類型的對象轉換為JSON格式的數據,Python對象類型向JSON數據類型轉換的對照表如下所示。json模塊Python對象類型說明JSON數據類型說明dict字
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 珍珠巖保溫板施工方案
- 挑腳手架施工方案
- 氟碳油漆施工方案
- 紫藤架修復施工方案
- 2025年度智能工廠用工承包協(xié)議書
- 二零二五年度醫(yī)院員工食堂運營管理協(xié)議
- 2025年度終止運輸合同書面通知樣本
- 2025年度物流運輸企業(yè)司機派遣合同模版
- 2025年餐飲行業(yè)臨時工福利待遇保障協(xié)議
- 2025年度智慧停車場委托管理及運營服務協(xié)議書
- JY-T 0470-2015 小學美術教學器材配備標準
- 燃氣安全裝置改造施工方案
- 北京市各縣區(qū)鄉(xiāng)鎮(zhèn)行政村村莊村名明細及行政區(qū)劃代碼
- 部編版一年級語文寫話教學講座培訓課件
- 項目部管理人員公路架橋機過孔旁站監(jiān)督確認記錄表
- 煤炭物流園區(qū)總體規(guī)劃(2016-2030)參考范本
- 混凝土構件之梁配筋計算表格(自動版)
- 道德與法治《上學路上》教案教學設計(公開課)
- TN-美國NFPA與中國國家消防規(guī)范比較手冊
- DB13(J)T 8359-2020 被動式超低能耗居住建筑節(jié)能設計標準(2021年版)
- 中學生文明禮儀主題班會PPT精美版課件
評論
0/150
提交評論