Python网页抓取教程
?— Python網(wǎng)頁抓取教程:循序漸進(jìn) —
抓取網(wǎng)頁入門其實(shí)挺簡單的。在之前的文章中我們介紹了怎么用C#和JAVA兩種方法來抓取網(wǎng)頁,這一期給大家介紹一種更容易,也是使用最廣泛的一種抓取方法,那就是Python。
說起Python,大家應(yīng)該并不陌生,它是目前入門最簡單的一種方法了,因?yàn)樗?strong>一種面向?qū)ο蟮恼Z言。Python的類和對象比任何其他語言都更容易使用。此外,Python存在許多庫,因而在Python中構(gòu)建用于網(wǎng)頁抓取的工具輕而易舉。
在這篇Python網(wǎng)絡(luò)抓取教程中,我們將分步驟講解如何利用python來抓取目標(biāo)數(shù)據(jù)。首先需要從頁面源獲取基于文本的數(shù)據(jù),然后將其存儲(chǔ)到文件中并根據(jù)設(shè)置的參數(shù)對輸出進(jìn)行排序。使用Python進(jìn)行網(wǎng)頁抓取時(shí)還有一些更高級功能的選項(xiàng),這些將在最后概述,并提供一些使用上的建議。按照教程下面概述的步驟進(jìn)行操作,您將能知道如何進(jìn)行網(wǎng)頁抓取。
Python網(wǎng)頁抓取教程適用于所有操作系統(tǒng)。不同系統(tǒng)安裝Python或開發(fā)環(huán)境時(shí)會(huì)略有不同,其它部分均無不同。
我們所說的網(wǎng)頁抓取是什么?
網(wǎng)絡(luò)抓取是收集公共數(shù)據(jù)的自動(dòng)化過程。爬蟲會(huì)在幾秒鐘內(nèi)自動(dòng)從目標(biāo)網(wǎng)站中提取大量公共數(shù)據(jù)。
#構(gòu)建網(wǎng)絡(luò)爬蟲:Python準(zhǔn)備工作
在整個(gè)網(wǎng)絡(luò)抓取教程中,將使用Python3.4以上版本,您可以此頁面下載。
準(zhǔn)確的說,我們使用了3.8.3,但任何3.4+版本都應(yīng)該可以正常運(yùn)行我們下面用到的代碼。
對于Windows系統(tǒng),安裝Python時(shí)確保選中“PATH安裝”。PATH安裝將可執(zhí)行項(xiàng)添加到默認(rèn)的Windows命令提示符可執(zhí)行項(xiàng)搜索中。然后Windows將識別諸如“pip”或“python”之類的命令,而無需用戶將其指向可執(zhí)行文件的目錄(例如C:/tools/python/.../python.exe)。如果您已經(jīng)安裝了Python但沒有勾選復(fù)選框,只需重新運(yùn)行安裝并選擇修改。在第二頁上選擇“添加到環(huán)境變量”即可。
了解Python庫
由于可用的許多有用的庫,使用Python進(jìn)行網(wǎng)頁抓取很容易。
Python的一大優(yōu)勢在于可供選擇的庫很多。這些網(wǎng)頁抓取用到的庫現(xiàn)在已經(jīng)用于數(shù)以萬計(jì)的Python項(xiàng)目——僅在PyPI上,現(xiàn)在就有超過300,000個(gè)項(xiàng)目。您可以選擇多種類型的Python網(wǎng)頁抓取庫:
●Requests
●Beautiful Soup
●lxml
●Selenium
01#Requests庫
網(wǎng)頁抓取首先向網(wǎng)站服務(wù)器發(fā)送HTTP請求(例如POST或GET ),該請求會(huì)返回一個(gè)包含所需數(shù)據(jù)的響應(yīng)。但是,標(biāo)準(zhǔn)Python HTTP庫難以使用,為了提高效率,需要大量代碼行,這進(jìn)一步加劇了已經(jīng)存在的問題。
與其他HTTP庫不同,Requests庫通過減少代碼行簡化了發(fā)出此類請求的過程,使代碼更易于理解和調(diào)試,而不會(huì)影響其有效性。使用pip命令就可以從終端內(nèi)安裝該庫:
pip install requestsRequests庫提供了發(fā)送HTTPGET和POST請求的簡單方法。例如,發(fā)送HTTP Get請求的函數(shù)被恰當(dāng)?shù)孛麨間et():
import requests response = requests.get("https://oxylabs.io/”) print(response.text)如果需要發(fā)布表單,可以使用post()方法輕松完成。表單數(shù)據(jù)可以作為字典發(fā)送,如下所示:
form_data = {'key1': 'value1', 'key2': 'value2'} response = requests.post("https://oxylabs.io/ ", data=form_data) print(response.text)請求庫還會(huì)使那些需要進(jìn)行身份驗(yàn)證的代理變得非常容易使用。
proxies={'http': 'http://user:password@proxy.oxylabs.io'} response = requests.get('http://httpbin.org/ip', proxies=proxies) print(response.text)但是這個(gè)庫有一個(gè)局限性,它不解析提取的HTML數(shù)據(jù),也就是說它不能將數(shù)據(jù)轉(zhuǎn)換成更易讀的格式進(jìn)行分析。此外,它不能用于抓取純JavaScript編寫的網(wǎng)站。
02#Beautiful Soup
Beautiful Soup是一個(gè)Python庫,它與解析器一起從HTML中提取數(shù)據(jù),甚至可以將無效標(biāo)記轉(zhuǎn)換為解析樹。但是,該庫僅用于解析,不能以HTML文檔/文件的形式從網(wǎng)絡(luò)服務(wù)器請求數(shù)據(jù)。它主要與Python Requests庫一起使用。需要注意的是,Beautiful Soup可以輕松查詢和導(dǎo)航HTML,但仍需要解析器。以下示例演示了html.parser模塊的使用,該模塊是Python標(biāo)準(zhǔn)庫的一部分。
#Part 1–使用Requests獲取HTML
import requests url='https://oxylabs.io/blog' response = requests.get(url)#Part 2–查找元素
from bs4 import BeautifulSoup soup = BeautifulSoup(response.text, 'html.parser') print(soup.title)標(biāo)題里的元素會(huì)輸出如下:
<h1 class="blog-header">Oxylabs Blog</h1>由于其導(dǎo)航、搜索和修改解析樹方法均很簡單,Beautiful Soup即使對于初學(xué)者也是十分不錯(cuò)的一個(gè)庫,并且通常可以節(jié)省開發(fā)人員數(shù)小時(shí)的工作時(shí)間。例如,要輸出此頁面中的所有博客標(biāo)題,就可以使用findAll()。在此頁面上,會(huì)找到所有h2大小,且類屬性為blog-card__content-title的博客標(biāo)題。該信息可以配合findAll方法使用,如下所示:
blog_titles = soup.findAll('h2', attrs={"class":"blog-card__content-title"}) for title in blog_titles:print(title.text) # Output: # Prints all blog tiles on the pageBeautifulSoup還可以輕松使用CSS selectors。如果開發(fā)人員知道CSS selector,則無需學(xué)習(xí)find()或find_all()方法。以下是相同的示例,但使用的是CSS selectors:
blog_titles = soup.select('h2.blog-card__content-title') for title in blog_titles: print(title.text)雖然能解析有問題的HTML是該庫的主要功能之一,但它還提供了許多其它功能,包括檢測頁面編碼,更進(jìn)一步提高從HTML文件中提取數(shù)據(jù)的準(zhǔn)確性。
更重要的是,它可以輕松配置,只需幾行代碼,即可提取任何自定義的公開可用數(shù)據(jù)或識別特定的數(shù)據(jù)類型。我們的Beautiful Soup教程包含有關(guān)此配置和其他配置的更多信息,以及該庫的工作原理。
03#lxml
lxml是一個(gè)解析庫。它是一個(gè)快速、強(qiáng)大且易于使用的庫,適用于HTML和XML文件。此外,lxml是大量提取數(shù)據(jù)的理想選擇。然而,與Beautiful Soup不同的是,這個(gè)庫針對設(shè)計(jì)的不好的HTML可能會(huì)出現(xiàn)解析不了的情況。
可以使用以下pip命令從終端安裝lxml庫:
pip install lxml這個(gè)庫包含一個(gè)html模塊來處理HTML。但是,lxml庫首先需要HTML字符串??梢允褂蒙弦还?jié)中討論的Requests庫檢索此HTML字符串。一旦HTML可用,就可以使用下面的fromstring方法構(gòu)建樹:
# After response = requests.get() from lxml import html tree = html.fromstring(response.text)現(xiàn)在可以使用XPath查詢此樹。繼續(xù)上一節(jié)中討論的示例,要獲取博客的標(biāo)題,XPath將如下所示:
//h2[@class="blog-card__content-title"]/text()可以將此XPath提供給tree.xpath()函數(shù)。這將返回與此XPath匹配的所有元素。注意XPath中的text()函數(shù)。該函數(shù)會(huì)提取h2元素內(nèi)的文本。
blog_titles = tree.xpath('//h2[@class="blog-card__content-title"]/text()') for title in blog_titles: print(title)假設(shè)您希望學(xué)習(xí)使用這個(gè)庫并將其集成到您的網(wǎng)絡(luò)抓取工作中,或者只是在您現(xiàn)有的專業(yè)知識基礎(chǔ)上學(xué)習(xí)更多知識。您可以參見更詳細(xì)的lxml教程。
04#Selenium
如上所述,一些網(wǎng)站是使用JavaScript編寫的,JavaScript是一種允許開發(fā)者動(dòng)態(tài)填充字段和菜單的語言。這給只能從靜態(tài)網(wǎng)頁中提取數(shù)據(jù)的Python庫帶來了問題。事實(shí)上,當(dāng)涉及到JavaScript時(shí),Requests庫將無法使用。這個(gè)時(shí)候就是Selenium網(wǎng)絡(luò)抓取的用武之地。
這個(gè)Python網(wǎng)絡(luò)庫是一個(gè)開源的瀏覽器自動(dòng)化工具(網(wǎng)絡(luò)驅(qū)動(dòng)),它允許您自動(dòng)執(zhí)行諸如登錄社交媒體平臺之類的過程。Selenium廣泛用于在應(yīng)用程序上測試案例或測試腳本。它在網(wǎng)頁抓取方面的優(yōu)勢源于它能夠像任何瀏覽器一樣通過運(yùn)行JavaScript來呈現(xiàn)網(wǎng)頁——標(biāo)準(zhǔn)的網(wǎng)絡(luò)爬蟲無法運(yùn)行這種編程語言。目前Selenium已被開發(fā)人員廣泛使用。
Selenium需要三個(gè)組件:
●瀏覽器–支持的瀏覽器有Chrome、Edge、Firefox和Safari。
●瀏覽器驅(qū)動(dòng)程序-請參閱此頁面以獲取驅(qū)動(dòng)程序的鏈接。
●Selenium安裝包。
可以從終端安裝selenium包:
pip install selenium安裝后,可以導(dǎo)入瀏覽器的相應(yīng)類。導(dǎo)入后,必須創(chuàng)建類的對象。注意,這將需要可執(zhí)行驅(qū)動(dòng)程序的路徑。Chrome瀏覽器示例如下:
from selenium.webdriver import Chrome driver = Chrome(executable_path='/path/to/driver')現(xiàn)在可以使用該get()方法在瀏覽器中加載任何頁面。
driver.get('https://oxylabs.io/blog')Selenium允許使用CSS Selectors和XPath來提取元素。以下示例使用CSS Selectors輸出所有博客標(biāo)題:
blog_titles = driver.get_elements_by_css_selector(' h2.blog-card__content-title') for title in blog_tiles: print(title.text) driver.quit() # closing the browser通過運(yùn)行JavaScript,Selenium可以處理動(dòng)態(tài)顯示的任何內(nèi)容,然后可用內(nèi)置方法甚至Beautiful Soup對網(wǎng)頁內(nèi)容進(jìn)行解析。此外,它還可以模仿用戶的行為。
在網(wǎng)絡(luò)抓取中使用Selenium的唯一缺點(diǎn)是它會(huì)減慢過程,因?yàn)樗仨毾葹槊總€(gè)頁面執(zhí)行JavaScript代碼,然后才能對其進(jìn)行解析。因此,它不適合大規(guī)模的數(shù)據(jù)提取。但是,如果您希望小規(guī)模提取數(shù)據(jù)或者不在乎數(shù)據(jù)提取速度,那么Selenium是一個(gè)不錯(cuò)的選擇。
支持網(wǎng)頁抓取的Python庫比較
對于這次的Python網(wǎng)頁抓取教程,我們將使用三個(gè)重要的庫——BeautifulSoup v4、Pandas和Selenium。請?zhí)崆鞍惭b好這些庫。如果您收到“NameError:name* is not defined”,則可能存在沒安裝成功的庫。
#網(wǎng)絡(luò)驅(qū)動(dòng)程序和瀏覽器
每個(gè)網(wǎng)絡(luò)爬蟲都會(huì)使用瀏覽器,因?yàn)樗枰B接到目標(biāo)URL。出于測試目的,我們強(qiáng)烈建議使用常規(guī)瀏覽器(或不是無頭瀏覽器),尤其是對于新手。查看編寫的代碼如何與應(yīng)用程序交互可以進(jìn)行簡單的故障排除和調(diào)試,也有助于更好地理解整個(gè)過程。
無頭瀏覽器可以在后面再使用,因?yàn)樗鼈儗τ?strong>復(fù)雜的任務(wù)更有效。在本次網(wǎng)頁抓取教程中,我們將使用Chrome瀏覽器,其實(shí)整個(gè)過程用Firefox瀏覽器也幾乎相同。
首先,使用您喜歡的搜索引擎查找“Chrome(或Firefox)的網(wǎng)絡(luò)驅(qū)動(dòng)”。記下您瀏覽器的當(dāng)前版本。下載與您的瀏覽器版本匹配的網(wǎng)絡(luò)驅(qū)動(dòng)程序。
如果適用,請選擇所需的軟件包,下載并解壓縮。將驅(qū)動(dòng)程序的可執(zhí)行文件復(fù)制到任何易于訪問的目錄即可。操作是否正確,后面運(yùn)行程序的時(shí)候就知道了。
為我們的Python網(wǎng)絡(luò)爬蟲尋找良好的編碼環(huán)境
在我們進(jìn)入本次網(wǎng)頁抓取教程的編程部分之前,需要采取最后一步:使用良好的編碼環(huán)境。有很多選擇,從簡單的文本編輯器(只需創(chuàng)建*.py文件并直接寫下代碼就足夠了),到功能齊全的IDE(集成開發(fā)環(huán)境)。
如果您已經(jīng)安裝了Visual Studio Code,選擇這個(gè)IDE將是最簡單的選擇。否則,我強(qiáng)烈建議新手使用PyCharm,因?yàn)樗鼛缀鯖]有入門門檻,并且有直觀的用戶界面。后面我們將使用PyCharm用于網(wǎng)頁抓取教程。
在PyCharm中,右鍵單擊項(xiàng)目區(qū)域并“新建->Python文件”。給它取個(gè)好聽的名字!
Part 1 導(dǎo)入和使用庫
是時(shí)候使用我們之前安裝的所有包了:
import pandas as pd from bs4 import BeautifulSoup from selenium import webdriverPyCharm可能會(huì)以灰色顯示這些導(dǎo)入,因?yàn)樗鼤?huì)自動(dòng)標(biāo)記未使用的庫。不要接受PyCharm刪除未使用的庫的建議。
首先,定義我們的瀏覽器。根據(jù)我們在“網(wǎng)絡(luò)驅(qū)動(dòng)和瀏覽器”中選擇的網(wǎng)絡(luò)驅(qū)動(dòng),我們應(yīng)該輸入:
driver = webdriver.Chrome(executable_path='c:\path\to\windows\webdriver\executable.exe') OR driver = webdriver.Firefox(executable_path='/nix/path/to/webdriver/executable')Part 2 選擇一個(gè)網(wǎng)址
Python網(wǎng)頁抓取需要查看網(wǎng)站的來源
在執(zhí)行我們第一次測試運(yùn)行之前,選擇一個(gè)URL。由于本次網(wǎng)頁抓取教程旨在創(chuàng)建一個(gè)基本應(yīng)用程序,我們強(qiáng)烈建議您選擇一個(gè)簡單的目標(biāo)URL:
●避開隱藏在Javascript元素中的數(shù)據(jù)。這些數(shù)據(jù)有時(shí)需要通過執(zhí)行特定操作來觸發(fā)才能顯示。從Javascript元素中抓取數(shù)據(jù)需要更復(fù)雜的Python使用方法及邏輯。
●避開抓取圖像。圖像可以直接用Selenium下載。
●在進(jìn)行任何抓取活動(dòng)之前,請確保您正在抓取的是公共數(shù)據(jù),并且絕不會(huì)侵犯第三方權(quán)利。另外,不要忘記查看robots.txt文件獲得指導(dǎo)。
選擇您要訪問的登錄頁面并將URL輸入到driver.get('URL')參數(shù)中。Selenium要求提供連接協(xié)議。因此,始終需要將“http://”或“https://”附加到URL上。
driver.get('https://your.url/here?yes=brilliant')嘗試通過單擊左下角的綠色箭頭或右鍵單擊編碼環(huán)境并選擇“運(yùn)行”來進(jìn)行測試運(yùn)行。
點(diǎn)擊紅色指針指到的地方
如果您收到一條錯(cuò)誤消息,指出文件丟失,請仔細(xì)檢查驅(qū)動(dòng)程序“webdriver.*”中提供的路徑是否與可執(zhí)行網(wǎng)絡(luò)驅(qū)動(dòng)的位置匹配。如果您收到版本不匹配的消息,請重新下載正確的可執(zhí)行網(wǎng)絡(luò)驅(qū)動(dòng)。
Part 3 定義對象和構(gòu)建列表
Python允許編碼人員在不指定確切類型的情況下設(shè)計(jì)對象。可以通過簡單地鍵入其標(biāo)題并分配一個(gè)值來創(chuàng)建對象。
# Object is “results”, brackets make the object an empty list. # We will be storing our data here. results = []Python中的列表是有序的、可變的并且允許復(fù)制列表中的成員。當(dāng)然您也可以使用其他集合,例如集合或字典。但列表是最容易使用的。下面我們先來添加一些對象。
# Add the page source to the variable `content`. content = driver.page_source # Load the contents of the page, its source, into BeautifulSoup # class, which analyzes the HTML as a nested data structure and allows to select # its elements by using various selectors. soup = BeautifulSoup(content)我們回顧一下之前已經(jīng)寫好的代碼:
import pandas as pd from bs4 import BeautifulSoup from selenium import webdriver driver = webdriver.Chrome(executable_path='/nix/path/to/webdriver/executable') driver.get('https://your.url/here?yes=brilliant') results = [] content = driver.page_source soup = BeautifulSoup(content)重新運(yùn)行應(yīng)用程序,不應(yīng)顯示任何錯(cuò)誤。如果出現(xiàn)任何問題,前面的章節(jié)中概述了一些可能的故障排除選項(xiàng)。
Part 4 使用Python網(wǎng)頁抓取工具提取數(shù)據(jù)
這部分有趣而又困難——從HTML文件中提取數(shù)據(jù)。由于幾乎在所有網(wǎng)頁下,我們都會(huì)從頁面的不同部分中提取需要的部分,并且我們希望將其存儲(chǔ)到列表中,因此我們需要處理每個(gè)小的部分,然后將其添加到列表中:
# Loop over all elements returned by the `findAll` call. It has the filter `attrs` given # to it in order to limit the data returned to those elements with a given class only. for element in soup.findAll(attrs={'class': 'list-item'}): ...“soup.findAll”可以接受各種參數(shù)。出于本教程的目的,我們僅使用“attrs”(屬性)參數(shù)。它允許我們通過設(shè)置一個(gè)語句“如果屬性等于X為真,則……”來縮小搜索范圍。很容易就能找到和使用尋找的類,我們下面將會(huì)用到該參數(shù)。
在繼續(xù)之前,讓我們在真實(shí)的瀏覽器中訪問所選的URL。然后使用CTRL+U(Chrome)打開頁面源代碼或右鍵單擊并選擇“查看頁面源代碼”。找到嵌套數(shù)據(jù)的“最近”類。另一種選擇是按F12打開開發(fā)者工具來選擇Element Picker。例如,它可以嵌套為:
<h4 class="title"><a href="...">This is a Title</a> </h4>我們的屬性“class”就是“title”。如果您選擇了一個(gè)簡單的目標(biāo),在大多數(shù)情況下,數(shù)據(jù)將以與上述示例類似的方式嵌套。獲取復(fù)雜的目標(biāo)數(shù)據(jù)可能需要更多嘗試。讓我們回到編碼并添加我們在源代碼中找到的類:
# Change ‘list-item’ to ‘title’. for element in soup.findAll(attrs={'class': 'title'}):...我們的循環(huán)現(xiàn)在將遍歷頁面源中具有“title”類的所有對象。我們會(huì)處理每一個(gè)對象:
name = element.find('a')讓我們看看我們的循環(huán)是如何遍歷HTML的:
<h4 class="title"><a href="...">This is a Title</a> </h4>我們的第一個(gè)語句(在循環(huán)本身中)查找所有匹配標(biāo)簽的元素,其“class”屬性包含“title”。然后我們在該類中執(zhí)行另一個(gè)搜索。我們的第二次搜索查找文檔中的所有標(biāo)簽(被包括在內(nèi),而像這樣的部分匹配則不被包括在內(nèi))。最后,對象被分配給變量“name”。
然后,我們可以將對象名稱分配給我們之前創(chuàng)建的列表數(shù)組“results”,但這樣做會(huì)將整個(gè)標(biāo)簽及其內(nèi)部的文本合并到一個(gè)元素中。在大多數(shù)情況下,我們只需要文本本身而不需要任何額外的標(biāo)簽。
# Add the object of “name” to the list “results”. # `.text` extracts the text in the element, omitting the HTML tags. results.append(name.text)我們的循環(huán)將遍歷整個(gè)頁面源,找到上面列出的所有出現(xiàn)的類,然后將嵌套數(shù)據(jù)附加到我們的列表中:
import pandas as pd from bs4 import BeautifulSoup from selenium import webdriver driver = webdriver.Chrome(executable_path='/nix/path/to/webdriver/executable') driver.get('https://your.url/here?yes=brilliant') results = [] content = driver.page_source soup = BeautifulSoup(content) for element in soup.findAll(attrs={'class': 'title'}): name = element.find('a') results.append(name.text)請注意,循環(huán)后的兩個(gè)語句是縮進(jìn)的。循環(huán)需要縮進(jìn)來表示嵌套。任何一致的縮進(jìn)都將被視為合法。沒有縮進(jìn)的循環(huán)將輸出“IndentationError”報(bào)錯(cuò),并用“箭頭”指出違規(guī)語句。
Part 5 導(dǎo)出數(shù)據(jù)
Python網(wǎng)頁抓取需要不斷仔細(xì)地檢查代碼
即使在運(yùn)行我們的程序時(shí)沒有出現(xiàn)語法或運(yùn)行時(shí)的錯(cuò)誤,仍然可能存在語義錯(cuò)誤。您需要檢查我們獲得的數(shù)據(jù)是不是分配給指定對象并正確移動(dòng)到數(shù)組的。
檢查您獲取的數(shù)據(jù)是否正確收集的最簡單方法之一是使用“print”。由于數(shù)組有許多不同的值,因此通常使用一個(gè)簡單的循環(huán)將每個(gè)條目分行進(jìn)行輸出:
for x in results:print(x)在這一點(diǎn)上,“print”和“for”是配合使用的。我們只是為了快速測試和調(diào)試目的進(jìn)行循環(huán)。直接輸出結(jié)果也是完全可行的:
print(results)到目前為止,我們的代碼應(yīng)該是這樣的:
driver = webdriver.Chrome(executable_path='/nix/path/to/webdriver/executable') driver.get('https://your.url/here?yes=brilliant') results = [] content = driver.page_source soup = BeautifulSoup(content) for a in soup.findAll(attrs={'class': 'class'}): name = a.find('a') if name not in results:results.append(name.text) for x in results: print(x)現(xiàn)在運(yùn)行我們的程序應(yīng)該不會(huì)報(bào)錯(cuò),調(diào)試窗口中也應(yīng)該會(huì)顯示獲取的數(shù)據(jù)。雖然“print”非常適合用于測試目的,但它對于解析和分析數(shù)據(jù)并不是很有用。
您可能已經(jīng)注意到,到目前為止,“import pandas”仍然是灰色的。我們最終還是會(huì)充分利用庫。建議現(xiàn)在刪除“print”循環(huán),因?yàn)榻酉聛砦覀円龅氖虑榕c此類似,并且會(huì)將數(shù)據(jù)移動(dòng)到csv文件。
df = pd.DataFrame({'Names': results}) df.to_csv('names.csv', index=False, encoding='utf-8')我們的兩個(gè)新語句依賴于pandas庫。我們的第一個(gè)語句創(chuàng)建了一個(gè)變量“df”并將其對象轉(zhuǎn)換為二維數(shù)據(jù)表。“Names”是我們列的名稱,而“results”是我們要輸出的列表。注意,pandas可以創(chuàng)建多個(gè)列,我們只是沒有足夠的列表來使用這些參數(shù)(目前)。
我們的第二個(gè)語句將變量“df”的數(shù)據(jù)移動(dòng)到特定的文件類型(在本例中為“csv”)。我們的第一個(gè)參數(shù)為我們即將創(chuàng)建的文件分配一個(gè)名稱和一個(gè)擴(kuò)展名。添加擴(kuò)展名是必要的,否則“pandas”將輸出一個(gè)沒有擴(kuò)展名的文件,并且必須手動(dòng)更改。“索引”可用于為列分配特定的起始編號。“編碼”用于以特定格式保存數(shù)據(jù)。一般情況下使用UTF-8就足夠了。
import pandas as pd from bs4 import BeautifulSoup from selenium import webdriver driver = webdriver.Chrome(executable_path='/nix/path/to/webdriver/executable') driver.get('https://your.url/here?yes=brilliant') results = [] content = driver.page_source soup = BeautifulSoup(content) for a in soup.findAll(attrs={'class': 'class'}): name = a.find('a') if name not in results:results.append(name.text) df = pd.DataFrame({'Names': results}) df.to_csv('names.csv', index=False, encoding='utf-8')現(xiàn)在所有導(dǎo)入的庫應(yīng)該都不是灰色的了,并且運(yùn)行我們的應(yīng)用程序可以將“names.csv”輸出到我們的項(xiàng)目目錄中。注意,“Guesed At Parser”警告仍然存在。我們可以通過安裝第三方解析器來刪除它,但對于本Python網(wǎng)頁抓取教程而言,默認(rèn)的HTML選項(xiàng)就可以了。
Part 6 更多清單
Python網(wǎng)頁抓取通常需要很多數(shù)據(jù)點(diǎn)
許多網(wǎng)頁抓取操作需要獲取多組數(shù)據(jù)。例如,僅提取電子商務(wù)網(wǎng)站上列出項(xiàng)目的標(biāo)題幾乎沒用。為了收集有意義的信息并從中得出結(jié)論,至少需要兩個(gè)數(shù)據(jù)點(diǎn)。
出于本教程的目的不同,我們將嘗試一些稍微不同的代碼。由于從同一個(gè)類中獲取數(shù)據(jù)只是意味著一個(gè)額外的列表,我們應(yīng)該嘗試從不同的類中提取數(shù)據(jù),但同時(shí)保持我們表的結(jié)構(gòu)。
顯然,我們需要另一個(gè)列表來存儲(chǔ)我們的數(shù)據(jù)。
import pandas as pd from bs4 import BeautifulSoup from selenium import webdriver driver = webdriver.Chrome(executable_path='/nix/path/to/webdriver/executable') driver.get('https://your.url/here?yes=brilliant') results = [] other_results = [] for b in soup.findAll(attrs={'class': 'otherclass'}): # Assume that data is nested in ‘span’. name2 = b.find('span') other_results.append(name.text)由于我們將從HTML的不同部分提取額外的數(shù)據(jù)點(diǎn),因此我們需要一個(gè)額外的循環(huán)。如果需要,我們還可以添加另一個(gè)“if”條件來控制重復(fù)條目:
最后,我們需要改變我們的數(shù)據(jù)表的形成方式:
df = pd.DataFrame({'Names': results, 'Categories': other_results})到目前為止,我們代碼的最新迭代應(yīng)該是這樣的:
import pandas as pd from bs4 import BeautifulSoup from selenium import webdriver driver = webdriver.Chrome(executable_path='/nix/path/to/webdriver/executable') driver.get('https://your.url/here?yes=brilliant') results = [] other_results = [] content = driver.page_source for a in soup.findAll(attrs={'class': 'class'}): name = a.find('a') if name not in results:results.append(name.text) for b in soup.findAll(attrs={'class': 'otherclass'}): name2 = b.find('span') other_results.append(name.text) df = pd.DataFrame({'Names': results, 'Categories': other_results}) df.to_csv('names.csv', index=False, encoding='utf-8')現(xiàn)在可以試試看,如果一切順利,運(yùn)行此代碼不會(huì)輸出任何錯(cuò)誤。在某些情況下,“pandas”會(huì)輸出“ValueError:arrays must all be the same length”報(bào)錯(cuò)消息。簡單來說,“results”和“other_results”列表的長度不相等,因此pandas無法創(chuàng)建二維表。
有多種方法可以解決該錯(cuò)誤消息。從用“空”值填充最短列表到創(chuàng)建字典,再到創(chuàng)建兩個(gè)系列并列出它們。我們選擇第三種做法:
series1 = pd.Series(results, name = 'Names') series2 = pd.Series(other_results, name = 'Categories') df = pd.DataFrame({'Names': series1, 'Categories': series2}) df.to_csv('names.csv', index=False, encoding='utf-8')請注意,數(shù)據(jù)不會(huì)匹配,因?yàn)榱斜黹L度不均勻,但如果需要兩個(gè)數(shù)據(jù)點(diǎn),創(chuàng)建兩個(gè)系列是最簡單的解決方法。我們的最終代碼應(yīng)該是這樣的:
import pandas as pd from bs4 import BeautifulSoup from selenium import webdriver driver = webdriver.Chrome(executable_path='/nix/path/to/webdriver/executable') driver.get('https://your.url/here?yes=brilliant') results = [] other_results = [] content = driver.page_source soup = BeautifulSoup(content) for a in soup.findAll(attrs={'class': 'class'}): name = a.find('a') if name not in results:results.append(name.text) for b in soup.findAll(attrs={'class': 'otherclass'}): name2 = b.find('span') other_results.append(name.text) series1 = pd.Series(results, name = 'Names') series2 = pd.Series(other_results, name = 'Categories') df = pd.DataFrame({'Names': series1, 'Categories': series2}) df.to_csv('names.csv', index=False, encoding='utf-8')運(yùn)行它會(huì)創(chuàng)建一個(gè)名為“names”的csv文件,其中包含兩列數(shù)據(jù)。
Part 7 使用Python進(jìn)行網(wǎng)絡(luò)抓取
我們的第一個(gè)網(wǎng)絡(luò)抓取工具現(xiàn)在應(yīng)該可以正常運(yùn)行了。整個(gè)過程很基礎(chǔ),也很簡單,所以執(zhí)行一些重要的數(shù)據(jù)采集時(shí)需要編譯更完善的代碼。在進(jìn)行更復(fù)雜的項(xiàng)目前,我強(qiáng)烈建議您嘗試一些附加功能:
●通過創(chuàng)建可生成偶數(shù)長度列表的循環(huán)來創(chuàng)建匹配的數(shù)據(jù)提取。
●一次性抓取多個(gè)URL。有很多方法可以實(shí)現(xiàn)這樣的功能。最簡單的選擇之一是簡單地重復(fù)上面的代碼并且每次更改URL。但是那樣很費(fèi)時(shí)間,也會(huì)很枯燥。可以構(gòu)建一個(gè)循環(huán)和一組要訪問的URL。
●另一種選擇是創(chuàng)建多個(gè)數(shù)組來存儲(chǔ)不同的數(shù)據(jù)集并將其輸出到具有不同行的一個(gè)文件中。一次抓取幾種不同類型的信息是電子商務(wù)數(shù)據(jù)獲取的重要組成部分。
●一旦運(yùn)行了令人滿意的網(wǎng)絡(luò)爬蟲,您就不再需要在用瀏覽器查看,而是直接執(zhí)行操作。獲取Chrome或Firefox瀏覽器的無頭版本,并使用它們來減少加載時(shí)間。
●創(chuàng)建爬取模式。想一想普通用戶如何瀏覽互聯(lián)網(wǎng)并嘗試模擬他們的操作。當(dāng)然這里會(huì)需要新的庫。使用“import time”和“from random import randint”來創(chuàng)建頁面之間的等待時(shí)間。添加“scrollto()”或使用特定的按鍵輸入在瀏覽器中移動(dòng)。在創(chuàng)建抓取模式時(shí),很難列出所有可能的選項(xiàng)。
●創(chuàng)建監(jiān)控流程。某些網(wǎng)站上的數(shù)據(jù)可能對時(shí)間(甚至用戶)敏感。嘗試創(chuàng)建一個(gè)持久的循環(huán),以設(shè)定的時(shí)間間隔重新檢查某些URL并抓取數(shù)據(jù)。確保您獲取的數(shù)據(jù)始終是最新的。
●使用Python Requests庫。Requests是網(wǎng)絡(luò)抓取工具包中的重要組成部分,因?yàn)樗试S優(yōu)化發(fā)送到服務(wù)器的HTTP請求。
●最后,將代理集成到您的網(wǎng)絡(luò)爬蟲中。使用特定位置的請求源允許您獲取可能無法訪問的數(shù)據(jù)。
—— 總結(jié) ——
看完我們的教程,您就可以自己寫一些代碼了。用Python構(gòu)建網(wǎng)絡(luò)爬蟲、獲取數(shù)據(jù)并從大量信息中得出結(jié)論其實(shí)是一個(gè)復(fù)雜但有趣的過程。
如果您想了解有關(guān)代理或高級數(shù)據(jù)采集工具如何工作的更多信息,或特定網(wǎng)絡(luò)抓取案例,例如:網(wǎng)絡(luò)抓取職位發(fā)布信息或構(gòu)建黃頁抓取工具的更多信息,請留意我們的微信,知乎和其它社交平臺。
我們準(zhǔn)備了不少優(yōu)質(zhì)的文章:
關(guān)于如何在抓取時(shí)避免封鎖的更詳細(xì)指南、網(wǎng)絡(luò)抓取是否合法、什么是代理的深入討論等等!
總結(jié)
以上是生活随笔為你收集整理的Python网页抓取教程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据库可视化软件 安装 for wind
- 下一篇: 《操作系统》OS学习(五):连续内存分配