




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
爬蟲和爬蟲的構成HTML和網絡基礎解析HTML文件獲取數據從網站獲取網頁urllib、requests直接獲取SeleniumScray爬蟲框架目錄1.1、獲取數據的重要性數據是大數據處理的基礎,獲取數據是數據處理和分析的第一步。1.2、如何獲取數據(1)從一些開源的網站上直接下載相關數據集,比如國外的kaggle和國內的阿里天池。(2)利用相關技術從網頁中抓取相關數據,比如爬蟲,然后利用獲得的數據進行相關數據分析工作。一、如何獲取數據/
數據集,例子程序,大數據處理競賽圖1阿里天池官網2.1、爬蟲的定義如果將互聯網比作一張大網,爬蟲就像是在網上爬行的蜘蛛。把每個頁面比作是一個個節點,網絡爬蟲訪問了該頁面并獲取了信息就相當于爬過了該節點。簡單來講,爬蟲就是一段自動抓取互聯網信息的程序,從互聯網抓取特定的信息
。二、什么是爬蟲圖2爬蟲定義爬蟲的組成爬蟲主要由4個模塊組成,包括爬蟲調度器,URL管理器(URL隊列),HTML下載器和HTML解析器。爬蟲調度器負責從URL管理器中取出需下載的URL,并啟動HTML下載器。HTML下載器訪問對應的URL并將獲取的內容存在本地或直接傳給HTML解析器處理。HTML解析器分析獲取的HTML文件內容,從中提取數據存入本地文件系統或數據庫中,并且從中提取需抓取的其他數據的URL放入URL管理器中。HTML下載和HTML解析是爬蟲設計的核心技術。圖3爬蟲的組成3.1、HTML頁面的獲取與響應瀏覽器和服務器之間采用的是HTTP(HyperTextTransferProtocol)協議傳輸網頁。傳輸的內容不局限于文本,圖片,音頻和各種js程序片段都可以通過這個協議傳輸。其傳輸過程如圖所示。三、HTML基本知識圖4HTTP傳輸過程選擇開發者工具后,在瀏覽器下方會出現開發者工具的選項。選中網絡后,在地址欄輸入百度的網址,在網絡選項卡中可以看到瀏覽器會發出幾十條請求。第一條是html文件,是百度的首頁,其他的包括css樣式表,png或jpeg的圖片,以及js腳本文件。開發者工具中的網絡工具詳細展示了瀏覽器和服務器之間的交互過程。從列表中可以看到訪問的狀態,訪問方式,訪問域名和文件,以及文件的類型,大小,傳輸時間等信息。利用火狐瀏覽器觀察網絡通信過程圖5通信過程單次請求請求方式常見的有GET,POST兩種類型,另外還有HEAD,PUT,DELETE,OPTIONS等。請求URLURL的全名是統一資源定位符。網絡上的一切資源都是位于服務器的某一個位置,而URL就是通知瀏覽器去哪里獲取這些資源請求頭請求頭(header)就是告訴服務器瀏覽器的版本,主機位置,緩存等,包括但不限于User-gaget,Host,Cookies等信息。服務器有時會檢查請求頭的內容,拒絕爬蟲的訪問等。通常需要在訪問時添加請求頭信息,保證請求合法。請求體請求時包含的額外數據,如POST請求需要輸入的表單數據,一般用于登錄,表單提交等。3.2、單次請求與響應(1)單個文件的獲取是發起請求(Request),并獲取服務器響應(Response)的過程。瀏覽器將包括URL在內的信息發送給對應的服務器,這個電文被稱為Request。服務器收到瀏覽器發送的消息后,根據瀏覽器發送消息的內容做響應的處理,并將結果發送給瀏覽器,這個電文被稱為Response。Request電文主要包括請求方式,請求網址,請求頭和請求體四個部分。且請求電文包含的內容如下:單次響應(2)從服務器獲取網頁的請求方式通常為GET和POST。GET方式一般用于獲取或者查詢資源信息,一般不需要傳入復雜的參數,響應速度快。POST方式可以在請求體中增加自定義的參數,并給出具體的值。這種方式常用于網站登錄和表單提交等場景。瀏覽器向服務器發出請求后,服務器就會返回一個響應(response)電文。響應電文的內容如下:響應狀態用于表示請求的結果,如200代表成功,404找不到頁面,502服務器錯誤等響應頭如內容類型,內容長度,服務器信息,設置Cookie等等響應體其實就是網頁源代碼,也就是用于解析數據的部分利用火狐瀏覽器查看請求內容我們首先打開火狐瀏覽器的開發者模式,然后在地址欄中輸入百度的網址。從請求來看,火狐瀏覽器增加了很多請求頭,請求的方法是GET。從響應來看,返回的狀態為200,返回的內容是一個html文件。圖6查看請求內容利用火狐瀏覽器查看響應內容點擊“響應”,就可以查看到本次請求從服務器端返回的響應內容。從圖中可以看出,當利用瀏覽器請求百度時,服務器端返回給客戶端百度首頁的HTML源碼,當瀏覽器接收到該響應內容之后,就會對源碼進行解析,并進行渲染,就會得到我們看到的百度首頁。圖7查看響應內容HTML網頁內容和結構3.3、HTML網頁內容和結構HTML(HyperTextMarkupLanguage),即超文本標記語言,描述了網頁的結構。現在的網頁一般都不是由單一的HTML文件組成。除了HTML文件以及其中引用的圖片外,通常還會用到控制頁面顯示狀態的層疊樣式表CSS和javascript腳本。圖8HTML網頁內容HTML解析的目的是從頁面中獲取數據和URL列表,一般可以用正則表達式提取網頁的信息,但是利用正則表達式的方式提取信息,顯得格外麻煩并且容易出錯。在Python中,第三方的BeautifulSoup,pyquery和lxml等庫都可以提取網頁信息。四、HTML頁面解析正則表達式(RegularExpression)是一段字符串,它可以表示一段有規律的信息。Python自帶一個正則表達式模塊,通過這個模塊可以查找、提取、替換一段有規律的信息。在程序開發中,要讓計算機程序從一大段文本中找到需要的內容,就可以使用正則表達式來實現,比如對于URL來說,可以使用[a-zA-z]+://[^\s]*來進行匹配。使用正則表達式有如下步驟。(1)尋找規律。(2)使用正則符號表示規律。(3)提取信息。4.1、使用正則表達式提取信息Python自1.5版本起增加了re模塊,它提供Perl風格的正則表達式模式。re模塊使Python語言擁有全部的正則表達式功能,如果需要使用該模塊,需要引入該模塊:importre。re模塊的主要函數如下表所示。4.1.1在Python中使用正則表達式函數名功能re.match()re.match()嘗試從字符串的起始位置匹配一個模式,成功返回一個Match對象。如果不是起始位置匹配成功的話,函數就返回none。re.search()re.search()掃描整個字符串并返回第一個成功匹配的Match對象。re.sub()re.sub()用于替換字符串中的匹配項pile()compile()函數用于編譯正則表達式,生成一個正則表達式(Pattern)對象,供match()和search()這兩個函數使用。re.finditer()在字符串中找到正則表達式所匹配的所有子串,并把它們作為一個迭代器返回。re.findall()在字符串中找到正則表達式所匹配的所有子串,并返回一個列表,如果沒有找到匹配的,則返回空列表。1.點號“.”
一個點號可以代替除了換行符以外的任何一個字符,包括但不限于英文字母、數字、漢字、英文標點符號和中文標點符號。2.星號“*”
一個星號可以表示它前面的一個子表達式(普通字符、另一個或幾個正則表達式符號)0次到無限次。3.問號“?”
問號表示它前面的子表達式0次或者1次。注意,這里的問號是英文問號。
4.反斜杠“\”
反斜杠在正則表達式里面不能單獨使用,甚至在整個Python里都不能單獨使用。反斜杠需要和其他的字符配合使用來把特殊符號變成普通符號,把普通符號變成特殊符號。5.數字“\d”
正則表達式里面使用“\d”來表示一位數字。為什么要用字母d呢?因為d是英文“digital(數字)”的首字母。
再次強調一下,“\d”雖然是由反斜杠和字母d構成的,但是要把“\d”看成一個正則表達式符號整體。
6.小括號“()”
小括號可以把括號里面的內容提取出來。4.1.2正則表達式的基本符號
反斜杠不僅可以把特殊符號變成普通符號,還可以把普通符號變成特殊符號。例如“n”只是一個普通的字母,但是“\n”代表換行符。在Python開發中,經常遇到的轉義字符,如下表所示。特殊符號字符描述\n匹配一個換行符。\s匹配任何空白字符,包括空格、制表符、換頁符等等。等價于[\f\n\r\t\v]。注意Unicode正則表達式會匹配全角空格符。\S匹配任何非空白字符。\t匹配一個制表符。\{匹配{。除此之外小括號,中括號的匹配也需要轉義符。(1)re.match函數:re.match(pattern,string,flags=0)參數:pattern:匹配的正則表達式string:要匹配的字符串flages:標志位,可選參數,用于控制正則表達式的匹配方式,如:是否區分大小寫,多行匹配等。(2)re.search()函數:re.search(pattern,string,flags=0)參數:和re.match()函數相同(re.match()只匹配字符串的開始,如果字符串開始不符合正則表達式,則匹配失敗,函數返回None;而re.search()匹配整個字符串,直到找到一個匹配)(3)re.sub()函數:re.sub(pattern,repl,string,count=0,flags=0)參數:pattern:匹配的正則表達式repl:被替換的字符串(既可以是字符串,也可以是函數)string:要匹配的字符串count:匹配的次數,默認是全部替換flags:標志位,可選參數,具體用法同re.match()函數詳解(1/2)(4)pile()函數:pile(pattern[,flags])參數:pattern:一個字符串形式的正則表達式flags:可選,表示匹配模式,用法同re.match()函數。(5)re.finditer()函數語法格式:re.finditer(pattern,string,flags=0)參數:用法同re.match()函數
(6)re.findall()函數語法格式:re.findall(pattern,string,flags=0)參數:用法同re.match()函數(match()和search()函數是匹配一次,而findall()函數匹配所有)函數詳解(2/2)在re模塊中的函數中基本上都會有一個flag參數,該參數是一個可選參數,指定了相關匹配控制模式。該參數的可選參數如表所示。在
Python
3.6
之后,以前的
re.S
等等的
flag
全部轉移到
RegexFlag
中了,所以有時候要改變用法
把
re.S
改寫成
re.RegexFlag.SFlag參數例1:使用正則表達式獲取<tr></tr>標簽之間的數據(ReTest01.py)<tr>標簽是位于<table>標簽內的,其代表表格中的一行,<tr>標簽中還會包括<td>標簽,其代表表格中的一個單元格,因此要獲取<tr>標簽中的內容,必須依次獲取<tr>中的內容,然后在獲取<td>中的內容,同時,對于一個表格來說,還會有表頭,因此可以通過獲取<th>標簽,來獲取表頭內容。例1程序運行結果:<th>西北工業大學</th><td>計算機學院</td>西北工業大學計算機學院例2:獲取超鏈接<ahref=..></a>之間內容(ReTest02.py)網頁中的超鏈接常常包含著一些重要的信息,同時還包含著超鏈接地址,因此,獲取網頁中的超鏈接地址顯得格外重要。要獲取網頁中的超鏈接部分,就必須通過尋找<ahref>標簽來獲取。例2程序運行結果:西北工業大學西北工業大學計算機學院//XPath(XMLPath)是一種查詢語言,它能在XML(ExtensibleMarkupLanguage,可擴展標記語言)和HTML的樹狀結構中尋找節點。在XPath中,有七種類型的節點(Node):元素、屬性、文本、命名空間、處理指令、注釋以及文檔(根)節點。在Python中,為了使用XPath,需要安裝一個第三方庫lxml:pipinstalllxml4.2使用XPath提取信息一個簡單的例子(Xpathexample.html)文檔中的節點:<html>(文檔節點)<title>西北工業大學</title>(元素節點)href=""(屬性節點)圖9Xpathexample.htmlHTML文件中的節點可以組成一棵樹。節點之間的關系包括父子,兄弟等。包含在一個節點內容的節點稱為該節點的子節點。在Xpathexample.html文件中,<body>和<head>就是<html>的子節點。每個節點有0個,1個或多個子節點。與之對應的是,除根節點外,每個節點都有一個父節點。具有相同父節點的節點互相為兄弟節點,例子中的<body>和<head>是兄弟節點。HTML的樹狀結構表達式描述nodename選取此節點的所有子節點。/從根節點選取。//從匹配選擇的當前節點選擇文檔中的節點,而不考慮它們的位置。.選取當前節點。..選取當前節點的父節點。@選取屬性。XPath使用路徑表達式在XML文檔中選取節點。節點是通過沿著路徑或者step來選取的。常見的路徑表達式如下表所示。Xpath表達路徑路徑表達式示例路徑表達式結果body選取body元素的所有子節點。/html選取根元素html。注:假如路徑起始于正斜杠(/),則此路徑始終代表到某元素的絕對路徑!body/p選取屬于html/body的子元素的所有p元素。//p選取所有p子元素,而不管它們在文檔中的位置。body//p選擇屬于body元素的后代的所有p元素,而不管它們位于body之下的什么位置。//@href選取名為href的所有屬性。路徑表達式示例在路徑表達式中可以用謂詞(Predicates)來查找某個特定的節點或者包含某個指定的值的節點。謂語被嵌在方括號中,限定和它相鄰的節點。下表列出了XPath路徑表達式謂詞的實例。路徑表達式中使用謂詞路徑表達式結果body/p[1]選取屬于body子元素的第一個p元素。/html/body/p[last()]選取屬于body子元素的最后一個p元素。body/p[last()-1]選取屬于bookstore子元素的倒數第二個book元素。//a[@href]選取所有擁有名為href的屬性的a元素。//div[@class=”abc”]選取所有div元素,且這些元素擁有值為abc的class屬性。通配符結果*匹配任何元素節點。@*匹配任何屬性節點。node()匹配任何類型的節點。通配符結果body/*選取bookstore元素的所有子元素。//*選取文檔中的所有元素。//a[@*]選取所有帶有屬性的a元素。使用通配符可以選取未知節點,上面的表列出了XPath路徑表達式中的通配符,下面的表列出了使用通配符及其獲取的結果。Xpath通配符1、讀取HTML文件并獲取所有節點(Xpath.py)fromlxmlimportetree##讀取html內容html=etree.parse("Xpathexample.html",etree.HTMLParser())result=etree.tostring(html)##獲取所有節點allnodes=html.xpath("http://*")print(allnodes)程序運行結果:[<Elementhtmlat0x1e9dcda1088>,<Elementheadat0x1e9dcd96ac8>,<Elementmetaat0x1e9dcd96888>,<Elementtitleat0x1e9dcd96788>,<Elementbodyat0x1e9dcd963c8>,<Elementpat0x1e9dcd96688>,<Elementbat0x1e9dcd96288>,<Elementpat0x1e9dcd96308>,<Elementaat0x1e9dcd96148>,<Elementpat0x1e9dcd96648>,<Elementaat0x1e9dcd960c8>]代碼實例2、獲取指定節點(Xpath.py)##獲取所有p節點all_p=html.xpath("http://p")print(all_p)程序運行結果:[<Elementpat0x1e9dcd96688>,<Elementpat0x1e9dcd96308>,<Elementpat0x1e9dcd96648>]代碼實例3、獲取子節點:通過/或者//可以查找元素的子節點或者子孫節點(Xpath.py)##選擇p節點的所有直接a子節點。child_a=html.xpath("http://p/a")print(child_a)程序運行結果:[<Elementaat0x1e9dca75848>,<Elementaat0x1e9dca75dc8>]代碼實例4、獲取父節點:如果我們知道了子節點,我們可以通過..的方式來獲取該子節點的父節點信息(Xpath.py)。parent_node=html.xpath('//a[@href=""]//../@class')print(parent_node)程序運行結果:['p1']代碼實例5、獲取節點中的文本信息:如果想獲取節點中的內容,可以通過xpath()函數中追加text()來獲取(Xpath.py)。#獲取ahref=所對應的內容content=html.xpath('//p/a[@href=""]/text()')print(content)程序運行結果:['西北工業大學首頁']代碼實例BeautifulSoup是一個可以從HTML或XML文件中提取數據的Python庫。它提供一些簡單的、python式的函數用來處理導航、搜索、修改分析樹等功能。它是一個工具箱,通過解析文檔為用戶提供需要抓取的數據,因為簡單,所以不需要多少代碼就可以寫出一個完整的應用程序。BeautifulSoup自動將輸入文檔轉換為Unicode編碼,輸出文檔轉換為utf-8編碼。BeautifulSoup已成為一個和lxml、html6lib一樣出色的python解釋器,為用戶靈活地提供不同的解析策略和強勁的速度。4.3使用BeautifulSoup提取信息解析器使用方法Python標準庫BeautifulSoup(markup,"html.parser")lxmlHTML解析器BeautifulSoup(markup,"lxml")lxmlXML解析器BeautifulSoup(markup,"xml")html5libBeautifulSoup(markup,"html5lib")BeautifulSoup支持Python標準庫中的HTML解析器,還支持一些第三方的解析器,其中一個是lxml,如果需要使用lxml解析器,則需要安裝lxml。另一個可供選擇的解析器是純Python實現的html5lib,html5lib的解析方式與瀏覽器相同。BeautifulSoup官網推薦使用lxml作為解析器,因為效率更高。BeautifulSoup支持的解析器如表所示。解析器BeautifulSoup將復雜HTML文檔轉換成一個復雜的樹形結構,每個節點都是Python對象,所有對象可以歸納為4種:Tag,NavigableString,BeautifulSoup,Comment。(1)Tag對象Tag對象與XML或HTML原生文檔中的tag相同。一個Tag可能包含多個字符串或其它的Tag,這些都是這個Tag的子節點。BeautifulSoup提供了許多操作和遍歷子節點的屬性。例(BeautifulSoup01.py):frombs4importBeautifulSoupsoup=BeautifulSoup('<bclass="boldest">西北工業大學</b>')tag=soup.bprint(type(tag))程序運行結果:<class'bs4.element.Tag'>對象的種類Tag對象有很多屬性,其中最重要的兩個屬性為:name和attributes。A、每一個Tag對象都有一個name,可以通過.name的方式獲取Tag對象的name。
Eg:print()#將打印出bB、也可以改變Tag對象的name屬性,如果改變了Tag對象的name,將影響所有通過當前BeautifulSoup對象生成的HTML文檔。Eg:="p"print(tag)程序將打印出<pclass="boldest">西北工業大學</p>C、attributes屬性指的是Tag對象的屬性,一個Tag對象可能有很多個屬性。比如<bclass="boldest">有一個“class”的屬性,值為“boldest”。可以通過.attrs來獲取屬性。Eg:print(tag.attrs)程序運行結果:{'class':['boldest’]}從程序的返回結果可以看出,tag.attrs返回的是一個python字典,所以Tag對象的有關屬性的相關操作和對字典的操作相同。Tag對象屬性例(BeautifulSoup01.py)#獲取class屬性的值print(tag["class"])#['boldest']#修改class屬性的值tag["class"]="nwpu"#增加一個id屬性tag["id"]="1"print(tag)#<pclass="nwpu"id="1">西北工業大學</p>#刪除id屬性deltag['id']print(tag)#<pclass="nwpu">西北工業大學</p>在獲取屬性時,可以通過tag.attrs['屬性值']的方式獲取,但是一般為了簡單,可以簡寫為tag['屬性值']。獲取class的屬性字符串常被包含在Tag對象內。BeautifulSoup用NavigableString類來包裝Tag對象中的字符串。例(BeautifulSoup01.py):print(tag.string)#西北工業大學print(type(tag.string))#<class'bs4.element.NavigableString’>tag中包含的字符串不能編輯,但是可以被替換成其它的字符串,用replace_with()方法。例(BeautifulSoup01.py):tag.string.replace_with("西北工業大學計算機學院")print(tag)#<pclass="nwpu">西北工業大學計算機學院</p>NavigableString對象BeautifulSoup對象表示的是一個文檔的全部內容。大部分時候,可以把它當作Tag對象。但是因為BeautifulSoup對象并不是真正的HTML或XML的Tag,所以它沒有name和attribute屬性。但是BeautifulSoup對象包含了一個值為“[document]”的特殊屬性name。例(BeautifulSoup01.py):print(type(soup))#<class'bs4.BeautifulSoup'>print()#[document]BeautifulSoup對象Tag,NavigableString,BeautifulSoup幾乎覆蓋了html和xml中的所有內容,但是還有一些特殊對象,比如注釋內容。此時,就要用到Comment對象。Comment對象是一個特殊類型的NavigableString對象。例(BeautifulSoup01.py):markup="<b><!--IamastudentofNWPU--></b>"soup=BeautifulSoup(markup)comment=soup.b.stringprint(type(comment))#<class'bs4.element.Comment'>print(comment)#IamastudentofNWPUComment對象1、子節點對于一個Tag對象,它可能包括多個字符串或者其它的Tag對象,這些都是這個Tag的子節點,在BeautifulSoup中提供了許多操作和遍歷子節點的屬性。在BeautifulSoup中,如果我們需要獲取某一個Html標簽,可以通過“soup.便簽名”的方式獲取(soup是一個BeautifulSoup對象,如soup.title)。同時,Tag對象有很多的屬性,可以很方便的供用戶調用。遍歷文檔樹示例文檔(BeautifulSoup02.py)html_doc="""<html><head><title>TheDormouse'sstory</title></head><pclass="title"><b>TheDormouse'sstory</b></p><pclass="story">Onceuponatimetherewerethreelittlesisters;andtheirnameswere<ahref="/elsie"class="sister"id="link1">Elsie</a>,<ahref="/lacie"class="sister"id="link2">Lacie</a>and<ahref="/tillie"class="sister"id="link3">Tillie</a>;andtheylivedatthebottomofawell.</p><pclass="story">...</p>"""frombs4importBeautifulSoupsoup=BeautifulSoup(html_doc)示例文檔Tag的contents屬性可以將Tag的子節點以列表的方式輸出,通過Tag的.children生成器,可以對tag的子節點進行循環。例(BeautifulSoup02.py):head_tag=soup.headprint(head_tag)#<head><title>TheDormouse'sstory</title></head>print(head_tag.contents)#[<title>TheDormouse'sstory</title>]title_tag=head_tag.contents[0]print(title_tag)#<title>TheDormouse'sstory</title>print(title_tag.contents)#["TheDormouse'sstory"]對于head_tag,它是一個Tag對象,head_tag.contents會將head_tag的子節點按照列表的形式列出,所以對于head_tag.contents的返回結果,其操作方式和python中的列表一致,且列表中保存的仍然是一個Tag對象。當調用children屬性時,獲取到的是一個迭代器,然后就可以通過循環的方式來遍歷迭代器中的內容。例(BeautifulSoup02.py):forchildintitle_tag.children:print(child)#TheDormouse'sstorycontents和childrencontents和children屬性僅包含Tag的直接子節點,例如,<head>標簽只有一個直接子節點<title>。如果想要獲取所以子孫節點的話,可以使用descendants屬性。例(BeautifulSoup02.py):print(type(head_tag.descendants))forchildinhead_tag.descendants:print(child)程序運行結果:<class'generator'><title>TheDormouse'sstory</title>TheDormouse'sstory從程序運行結果可以看出,head_tag.descendants是一個generator對象,對于這個對象,可以利用for循環進行遍歷。在給出的例子中,<head>標簽只有一個子節點,但是有2個子孫節點:<head>節點和<head>的子節點<title>。descendantsParent:如果想獲取某個元素的父節點,可以通過parent屬性來獲取。比如,在給出的文檔中,<head>標簽是<title>標簽的父節點。例(BeautifulSoup02.py):print(title_tag.parent)#<head><title>TheDormouse'sstory</title></head>一個文檔的頂層節點,比如<html>的父節點是BeautifulSoup對象,對于BeautifulSoup對象的parent屬性是None。例(BeautifulSoup02.py):html_tag=soup.htmlprint(type(html_tag.parent))#<class'bs4.BeautifulSoup'>print(soup.parent)#None父節點和祖先節點Parents:通過元素的parents屬性可以遞歸得到元素的所有父輩節點。例(BeautifulSoup02.py):#遍歷<a>便簽到根節點的所有節點。link=soup.aprint(link)forparentinlink.parents:ifparentisNone:print(parent)else:print()程序運行結果:<aclass="sister"href="/elsie"id="link1">Elsie</a>pbodyhtml[document]父節點和祖先節點兄弟節點就是當前節點的同級節點,比如“<a><b>text1</b><c>text2</c></b></a>”,因為<b>標簽和<c>標簽是同一層:他們是同一個元素的子節點,所以<b>和<c>可以被稱為兄弟節點。next_sibling和previous_sibling:在文檔樹中,使用next_sibling和previous_sibling屬性來查詢兄弟節點。例(BeautifulSoup02.py):sibling_soup=BeautifulSoup("<a><b>text1</b><c>text2</c></b></a>")print(sibling_soup.b.next_sibling)#<c>text2</c>print(sibling_soup.c.previous_sibling)#<b>text1</b><b>標簽有next_sibling屬性,但是沒有previous_sibling屬性,因為<b>標簽在同級節點中是第一個。同理,<c>標簽有previous_sibling屬性,卻沒有next_sibling屬性。兄弟節點next_siblings和previous_siblings:通過next_siblings和previous_siblings屬性可以對當前節點的兄弟節點迭代輸出例(BeautifulSoup02.py):forsiblinginsoup.a.next_siblings:print(repr(sibling))forsiblinginsoup.find(id="link3").previous_siblings:print(repr(sibling))程序運行結果:',\n'<aclass="sister"href="/lacie"id="link2">Lacie</a>'and\n'<aclass="sister"href="/tillie"id="link3">Tillie</a>';\nandtheylivedatthebottomofawell.''and\n'<aclass="sister"href="/lacie"id="link2">Lacie</a>',\n'<aclass="sister"href="/elsie"id="link1">Elsie</a>'Onceuponatimetherewerethreelittlesisters;andtheirnameswere\n兄弟節點BeautifulSoup定義了很多搜索方法,這些方法可以很方便的使我們定位到某一個標簽,其中最重要的兩個方法就是find()和find_all()。find_all()函數:find_all()方法搜索當前tag的所有tag子節點,并判斷是否符合過濾器的條件,過濾器可以是一個字符串、也可以是一個正則表達式、也可以是一個列表、也可以是一個布爾值,同時也可以定義為一個函數,其目的就是讓find_all()函數搜索出所以符合條件的標簽。其函數原型為:find_all(name,attrs,recursive,text,**kwargs)搜索文檔樹name參數:傳入name參數,可以按照節點的名稱進行查詢元素。attrs參數:除了根據節點名查詢,我么也可以傳入一些屬性來查詢。當傳入attrs參數時,參數的類型應該是一個字典類型。recursive參數:調用Tag對象的find_all()方法時,BeautifulSoup會檢索當前Tag的所有子孫節點,如果只想搜索Tag的直接子節點,可以使用參數recursive=False。text參數:text參數可用來匹配節點的文本,傳入的形式可以是字符串,也可以是正則表達式對象,也可以是一個列表,也可以是一個函數。find_all()函數參數find()函數與find_all()函數用法大致相似。其函數原型為:find(name,attrs,recursive,text,**kwargs)但是find()函數只返回單個元素,也就是第一個匹配的元素,而find_all()函數返回的是所以匹配元素組成的列表。例:查找標簽為p的第一個匹配元素(BeautifulSoup02.py)print(soup.find('p'))print(type(soup.find('p')))程序運行結果:<pclass="title"><b>TheDormouse'sstory</b></p><class'bs4.element.Tag'>find()函數除了find_all()和find()方法,BeautifulSoup中還有其它10個用于搜索的API。其用法以及參數與find_all()和find()函數相似。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():其者返回節點前所有符合條件的節點,后者返回第一個符合條件的節點。其他搜索函數豆瓣Top250頁面部分源碼利用BeautifulSoup分析豆瓣電影榜圖10豆瓣Top250部分源碼分析對于每一個電影信息,都在一個div中,且該div的class均設置為pl2,在div標簽中,包含了很多子標簽,對于電影名稱包含在第一個a標簽中,上映時間主演等信息包含在p標簽中,每一個電影的評分包含在class為starclearfix的div標簽的span子標簽中,且該span子標簽的class為p1。通過以上分析,我們就能夠清晰地掌握該html的結構,然后我們就可以通過這些特征對該html文檔進行分析,提取出有關信息。分析代碼(douban.py)程序運行結果:{'地久天長':7.9,'綠皮書':8.9,'孟買酒店':8.4,'調音師':8.3,'雪暴':6.2,'我們':6.5,'海市蜃樓':7.8,'五尺天涯':8.0,'我的一級兄弟':8.2,'反貪風暴4':6.0}代碼爬蟲首先要做的工作就是獲取網頁,這里就是獲取網頁源代碼。源代碼里包含了網頁的部分有用信息,所以只要把源代碼獲取下來,就可以從中提取想要的信息了。我們可以從網頁中抓取的數據有網頁文本、圖片、視頻等。Python語言提供了許多庫來幫助我們實現截取網頁源碼,如urllib、requests等。我們可以用這些庫來幫助我們實現HTTP請求操作,請求和響應都可以用類庫提供的數據結構來表示,得到響應之后需要解析數據結構中的Body部分即可,即可得到網頁源代碼,這樣我們就可以通過程序來實現獲取網頁的過程。使用爬蟲基本庫,我們只需關心請求的鏈接是什么,需要傳的參數是什么,以及如何設置可選的請求頭就好了,不用深入到底層去了解它到底是怎樣傳輸和通信的。有了它,兩三行代碼就能夠完成一個請求和響應的處理過程,得到網頁的內容。五、頁面獲取urllib庫是Python內置的HTTP請求庫,也就是說我們不需要額外安裝即可使用,它包含四個模塊,如表所示1、使用urllib模塊名功能urllib.request可以用來發送request和獲取request的結果urllib.error包含了urllib.request產生的異常urllib.parse包含了urllib.request產生的異urllib.robotparse用來解析頁面的robots.txt文件,很少使用使用Urllib的request模塊我們可以方便地實現Request的發送并得到Response。urlopen()函數原型:urllib.request.urlopen(url,data=None,[timeout,]*,cafile=None,capath=None,cadefault=False,context=None)urllib.request模塊提供了最基本的構造HTTP請求的方法,利用它可以模擬瀏覽器的一個請求發起過程,同時它還帶有處理authenticaton(授權驗證),redirections(重定向),cookies(瀏覽器Cookies)以及其它內容。例:抓取百度首頁(urllib01.py):importurllib.requestresponse=urllib.request.urlopen("")print(response.read().decode("utf-8"))Reponse是一個HTTPResposne類型的對象,它主要包含的方法有read()、readinto()、getheader(name)、getheaders()、fileno()等方法和msg、version、status、reason、debuglevel、closed等屬性。發送請求——urlopen()Urllib.request.Request類是URL請求的抽象,該類的構造方法如下:classurllib.request.Request(url,data=None,headers={},origin_req_host=None,unverifiable=False,method=None)參數詳解A.第一個參數是url,它是一個字符串類型且必須是一個有效的URL,該參數是一個必須參數。B.第二個參數data必須是指定要發送到服務器的其他數據的對象,如果不需要此類數據,則為None。目前,HTTP請求是唯一使用數據的請求。支持的對象類型包括字節,類文件對象和可迭代。C.第三個參數header必須是一個字典類型,它是請求頭。D.第四個參數origin_req_host是請求方的host名稱或者IP地址。E.第五個參數unverifiable表示該請求是否無法核實,默認為false。無法驗證的請求就是指用戶沒有權限去接受請求。F.第六個參數method是一個字符串,用來指示請求使用的方法,比如GET、POST和PUT等。發送請求——Request例(urllib02.py):fromurllibimportrequest,parseurl="/post"headers={"User-Agent":"Mozilla/4.0(compatible;MSIE5.5;WindowsNT)","Host":""}di={"name":"Germey"}data=bytes(parse.urlencode(di),encoding="utf-8")req=request.Request(url=url,data=data,headers=headers,method="POST")response=request.urlopen(req)print(response.read().decode("utf-8"))Request使用案例Request使用案例程序運行結果urllib.error模塊為urllib.request引發的異常定義了異常類。基本異常類是URLError。exceptionurllib.error.URLError:處理程序遇到問題時會引發此異常(或派生異常)。它是OSError的子類。Request模塊產生的所有異常都可以由該類來進行捕獲。Reason屬性可以查看異常的相關信息例:解析不存在的鏈接(urllib03.py)fromurllibimportrequest,errortry:response=request.urlopen("")excepterror.URLErrorasex:print(ex.reason)程序請求打開,但是實際上這個網址是不存在的,所以將會拋出URLError異常,reason屬性將會顯示異常類型為NotFound,所以程序運行結果將是“NotFound”。處理異常——exceptionurllib.error.URLErrorHTTPError是URLError的一個子類,可以作為一個非特殊的文件類返回值(與urlopen()返回的相同)。在處理異常HTTP錯誤(例如身份驗證請求)時非常有用。該類有三個屬性:A、code:返回HTTP的狀態碼,例如400表示頁面不存在,500表示服務器錯誤。B、reason:返回錯誤原因。C、headers:返回請求頭信息。例:解析錯誤連接(urllib04.py)fromurllibimportrequest,errortry:responserequest.urlopen("/pandas-docs/stabl")excepterror.HTTPErrorasex:print(ex.reason,ex.code,ex.headers,sep="\n")程序請求打開pandas官方文檔,但是誤將網址的最后一個單詞“stable”寫成了“stabl”,由于網址無法解析,所以程序捕獲到了異常,并打印出相關異常信息。處理異常——exceptionurllib.error.HTTPErrorurllib.parse模塊定義了一個標準接口,用于在組件中解析統一資源定位符(URL)字符串(尋址方案,網絡位置,路徑等),將組件組合回URL字符串,并將“相對URL”轉換為絕對URL給出“基本URL”。它支持以下URL方案:file,ftp,gopher,hdl,http,https,imap,mailto,mms,news,nntp,prospero,rsync,rtsp,rtspu,sftp,shttp,sIP,sIPs,snews,svn,svn+ssh,telnet,wais,ws,wss。urllib.parse模塊定義的功能分為兩大類:URL解析和URL引用。解析鏈接urlparse()函數側重于將URL字符串拆分url組件,或者將url組件組合為URL字符串。其函數原型如下:urllib.parse.urlparse(urlstring,scheme='',allow_fragments=True)urlparse()函數將一個url拆分為6個部分,其中包括scheme(協議名稱)、netloc(域名)、path(訪問路徑)、params(訪問參數)、query(查詢條件)和fragment(錨點)。函數包含三個參數,第一個參數urlstring是必須的,代表的是需要解析的url地址;第二個參數scheme代指使用的協議,默認為https;第三個參數allow_fragments表示是否忽略fragment,默認為True。例:解析url(urllib05.py)fromurllib.parseimporturlparseo=urlparse('http://www.cwi.nl:80/%7Eguido/Python.html')print(o)print(o.scheme)print(o.port)print(o.geturl)urlparse()對于現有的一串GET請求參數,該函數可以將其轉化為字典,其函數原型如下:urllib.parse.parse_qs(qs,keep_blank_values=False,strict_parsing=False,encoding='utf-8',errors='replace',max_num_fields=None)參數詳解A、參數qs是必填項,指定需要轉化的請求參數。B、可選參數keep_blank_values是一個標志,指示百分比編碼查詢中的空值是否應被視為空字符串,默認為False。C、可選參數strict_parsing是一個標志,指示如何處理解析錯誤。如果為false(默認值),則會以忽略錯誤D、可選的encoding和errors參數指定如何將百分比編碼的序列解碼為Unicode字符。E、可選參數max_num_fields是要讀取的最大字段數。例(urllib06.py):fromurllib.parseimportparse_qsquery="school=nwpu&&loc=shanxi"print(parse_qs(query))##{'school':['nwpu'],'loc':['shanxi']}parse_qs()該函數的原型為:urllib.parse.urlunparse(parts),該函數從urlparse()返回的元組中構造URL例(urllib07.py):fromurllib.parseimporturlunparsedata=["http","","index.html","user","a=7","comment"]print(urlunparse(data))運行結果:/index.html;user?a=7#commenturlunparse()urlsplit()函數的原型如下:urllib.parse.urlsplit(urlstring,scheme='',allow_fragments=True)該函數和urlparse()類似,但不會從URL中拆分params。因此只會返回5個結果。例(urllib08.py):fromurllib.parseimporturlsplitresult=urlsplit("/index.html")print(result)運行結果:SplitResult(scheme='http',netloc='',path='/index.html',query='',fragment=‘’)可以發現,在返回的元組中沒有params參數,僅僅返回了5個結果。urlsplit()該函數的原型為:urllib.parse.urlunsplit(parts)該函數將urlsplit()返回的元組元素組合成一個完整的URL。該函數與urlunparse很相似,唯一的區別在于傳入的可迭代對象長度必須是5。例(urllib09.py):fromurllib.parseimporturlunsplitdata=["http","","index.html","a=7","comment"]print(urlunsplit(data))運行結果:/index.html?a=7#commenturlunsplit()在使用requests庫之前,我們需要安裝requests庫,安裝方法可以通過pip或者conda命令進行安裝,安裝成功之后,即可使用requests庫:pipinstallrequests或condainstallrequests2、使用requests庫圖9安裝requests使用requests發送網絡請求非常簡單,一開始需要導入requests模塊,然后獲取某個網頁。我們以獲取百度首頁信息為例:例(requests01.py):importrequestsr=requests.get("")有了一個名為r的Response對象,就可以從這個對象中獲取我們想要的信息。例(requests01.py):print(type(r))print(r.status_code)print(r.cookies)運行結果:<class'requests.models.Response’>200<RequestsCookieJar[<CookieBDORZ=27315for./>]>發送請求需要為URL的查詢字符串傳遞某種數據,通常我們可以手工來構建URL,那么數據就會以鍵值對的形式置于URL中,跟在一個問號后面,例如,/get?key=val。在requests庫中,可以通過params關鍵字來傳遞參數,該參數通常以一個字符串字典的形式傳入。例(requests02.py):importrequestsparams={'key1':'value1','key2':'value2'}r=requests.get("/get",params=params)print(r.url)#打印出/get?key1=value1&key2=value2傳遞URL參數客戶端向服務器端發送請求之后,服務器端會給客戶端一個響應,我們可以通過requests庫來讀取服務器響應的內容。例(requests03.py):importrequestsr=requests.get('’)r.text該程序運行之后,將返回百度首頁的html內容。Requests能夠自動解碼來自服務器的內容,大多數unicode字符集都能夠被解碼。當請求發出后,requests會基于HTTP頭部對響應的編碼作出有根據的推測,當訪問r.text時,requests會根據其推測的進行文本編碼。響應內容客戶端向服務器端發送請求之后,服務器端會給客戶端一個響應,我們可以通過requests庫來讀取服務器響應的內容。例:給相應的請求添加content-type(requests04.py)importrequestsurl='/some/endpoint'headers={'user-agent':'my-app/0.0.1'}r=requests.get(url,headers=headers)Requests不會基于定制header的具體情況而改變自己的行為,只不過在最后的請求中,所有的header信息都會被傳遞進去,在request中,所有的header的值必須是string、bytestring或者unicode。如果想要查看某個請求的請求頭,可以通過headers屬性來查看。定制請求頭Selenium是一個自動化測試工具,利用它可以驅動瀏覽器執行特定的動作,比如點擊、下拉等操作,同時還可以獲取瀏覽器當前呈現的頁面的源代碼,做到可見即可爬。用戶可以通過命令pipinstallselenium進行安裝。安裝完selenium之后,我們還需要下載ChromeDriver,我們使用的版本是2.30,可以進入/mirrors/chromedriver/網站下載。3、使用Selenium獲取網頁圖10ChromeDriver版本在利用selenium獲取源代碼之前,我們需要將下載的ChromeDriver與代碼放在同一個文件夾下,以便調用。如果將其放在別的路徑下,就需要使用絕對路徑進行調用。例(selenium01.py):#獲取百度源碼#初始化selenium并導入selenium庫fromseleniumimportwebdriver#使用相對路徑指定WebDriverdriver=webdriver.Chrome('chromedriver.exe')try:#使用selenium打開網頁
driver.get('')#獲取網頁源代碼
html=driver.page_source
print(html)#打印網頁源代碼finally:driver.close()獲取源代碼Selenium支持非常多的瀏覽器,如Chrome、Firefox、Edge、Safari等,也支持無界面瀏覽器PhantomJS,我們在初始化時可以進行指定。例:driver=webdriver.Chrome()driver=webdriver.Firefox()driver=webdriver.Edge()driver=webdriver.PhantomJS()driver=webdriver.Safari()聲明瀏覽器類型如果想獲取網頁中的單個節點元素,Selenium也提供了很多方法。其中最常用的兩個為:□find_element_by_id():通過id獲取,返回符合條件的第一個□find_element_by_name():通過name獲取,返回符合條件的第一個例:獲取百度首頁搜索框節點獲取單個元素圖10百度首頁部分源碼可以看出,該搜索框的id為kw,name為wd。代碼例:獲取百度首頁搜索框節點(selenium02.py)fromseleniumimportwebdriver#使用相對路徑指定WebDriverdriver=webdriver.Chrome('chromedriver.exe')driver.get('')element_by_name=driver.find_element_by_name('wd')element_by_id=driver.find_element_by_id('kw')print(element_by_name)print(element_by_id)driver.close()程序運行結果:<selenium.webdriver.remote.webelement.WebElement(session="8b071cb473e7717c25e90e0837df1adc",element="324c4d3f-5a07-4a30-86a4-f0999bab27c6")><selenium.webdriver.remote.webelement.WebElement(session="8b071cb473e7717c25e90e0837df1adc",element="324c4d3f-5a07-4a30-86a4-f0999bab27c6")>find_element_by_link_text:通過標簽中的元素文本鏈接查找單個元素find_element_tag_name:通過標簽名獲取單個元素find_element_by_class_name:通過class屬性名獲取單個元素find_element_by_css_selector:通過css選擇器獲取單個元素find_element_by_xpath:通過xpath的方式獲取單個元素Selenium還提供了一個find_element()方法,該方法也是獲取單個元素節點,該方法需要傳入兩個參數,第一個參數是查找方式,第二個參數是查找的值。比如通過id
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
評論
0/150
提交評論