您好,登錄后才能下訂單哦!
本篇內容主要講解“怎么使用Python從任何網站抓取數據”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“怎么使用Python從任何網站抓取數據”吧!
首先,我應該警告您網絡抓取的合法性。雖然抓取行為是合法的,但您可能提取的數據使用可能是非法的。確保你沒有爬取:
受版權保護的內容 – 由于它是某人的知識產權,因此受法律保護,您不能只是重復使用它。
個人數據——如果您收集的信息可用于識別個人身份,則它被視為個人數據,對于歐盟公民而言,它受 GDPR 保護。除非您有合法的理由來存儲這些數據,否則最好完全跳過它。
一般來說,在抓取之前,您應該始終閱讀網站的條款和條件,以確保您不會違反他們的政策。如果您不確定如何繼續,請聯系網站所有者并征求同意。
要開始構建您自己的網絡爬蟲,您首先需要在您的機器上安裝Python。Ubuntu 20.04 和其他版本的 Linux 預裝了 Python 3。
要檢查您的設備上是否已經安裝了 Python,請運行以下命令:
python3 -v
如果您安裝了 Python,您應該會收到類似如下輸出:
Python 3.8.2
此外,對于我們的網絡爬蟲,我們將使用 Python 包 BeautifulSoup(用于選擇特定數據)和 Selenium(用于呈現動態加載的內容)。要安裝它們,只需運行以下命令:
pip3 install beautifulsoup4
和
pip3 install selenium
最后一步是確保在您的機器上安裝了 Google Chrome和Chrome 驅動程序。如果我們想使用 Selenium 抓取動態加載的內容,這些將是必要的。
使用火狐瀏覽器或者其他瀏覽器也需要對應的瀏覽器驅動。
現在你已經安裝了所有東西,是時候開始我們的抓取項目了。
您應該根據需要選擇要抓取的網站。請記住,每個網站的內容結構都不同,因此當您開始自己抓取時,您需要調整在此處學到的內容。每個網站都需要對代碼進行細微的更改。
對于本文,我決定從 IMDb 的前 250 部電影列表中抓取前十部電影的信息:https : //www.imdb.com/chart/top/。
首先,我們將獲得標題,然后我們將通過從每部電影的頁面中提取信息來進一步深入研究。一些數據將需要 JavaScript 呈現。
要開始了解內容的結構,您應該右鍵單擊列表中的第一個標題,然后選擇“檢查元素”。
通過按 CTRL+F 并在 HTML 代碼結構中搜索,您將看到頁面上只有一個<table>標記。這很有用,因為它為我們提供了有關如何訪問數據的信息。
一個 HTML 選擇器將為我們提供頁面中的所有標題table tbody tr td.titleColumn a
。那是因為所有標題都位于具有“titleColumn
”類的表格單元格內的錨點中。
使用這個 CSS 選擇器并獲取每個錨點的innerText
將為我們提供我們需要的標題。您可以在剛剛打開的新窗口中使用 JavaScript 行在瀏覽器控制臺中模擬:
document.querySelectorAll("table tbody tr td.titleColumn a")[0].innerText
你會看到這樣的結果:
現在我們有了這個選擇器,我們可以開始編寫 Python 代碼并提取我們需要的信息。
我們列表中的電影標題是靜態內容。這是因為如果您查看頁面源代碼(頁面上的 CTRL+U 或右鍵單擊然后選擇查看頁面源代碼),您將看到標題已經存在。
靜態內容通常更容易抓取,因為它不需要 JavaScript 渲染。為了提取列表中的前十個標題,我們將使用 BeautifulSoup 獲取內容,然后將其打印在我們的Scraper的輸出中。
import requests
from bs4 import BeautifulSoup
page = requests.get('https://www.imdb.com/chart/top/') # Getting page HTML through request
soup = BeautifulSoup(page.content, 'html.parser') # Parsing content using beautifulsoup
links = soup.select("table tbody tr td.titleColumn a") # Selecting all of the anchors with titles
first10 = links[:10] # Keep only the first 10 anchors
for anchor in first10:
print(anchor.text) # Display the innerText of each anchor
上面的代碼使用我們在第一步中看到的選擇器從頁面中提取電影標題錨點。然后循環遍歷前十個并顯示每個的innerText。
輸出應如下所示:
隨著技術的進步,網站開始動態加載其內容。這提高了頁面的性能、用戶的體驗,甚至消除了爬蟲的額外障礙。
但是,這使事情變得復雜,因為從簡單請求中檢索到的 HTML 將不包含動態內容。幸運的是,有了Selenium,我們可以在瀏覽器中模擬一個請求,等待動態內容顯示出來。
您需要知道 chromedriver 的位置。以下代碼與第二步中的代碼相同,但這次我們使用 Selenium 發出請求。我們仍然會像以前一樣使用 BeautifulSoup 解析頁面的內容。
from bs4 import BeautifulSoup
from selenium import webdriver
option = webdriver.ChromeOptions()
# I use the following options as my machine is a window subsystem linux.
# I recommend to use the headless option at least, out of the 3
option.add_argument('--headless')
option.add_argument('--no-sandbox')
option.add_argument('--disable-dev-sh-usage')
# Replace YOUR-PATH-TO-CHROMEDRIVER with your chromedriver location
driver = webdriver.Chrome('YOUR-PATH-TO-CHROMEDRIVER', options=option)
driver.get('https://www.imdb.com/chart/top/') # Getting page HTML through request
soup = BeautifulSoup(driver.page_source, 'html.parser') # Parsing content using beautifulsoup. Notice driver.page_source instead of page.content
links = soup.select("table tbody tr td.titleColumn a") # Selecting all of the anchors with titles
first10 = links[:10] # Keep only the first 10 anchors
for anchor in first10:
print(anchor.text) # Display the innerText of each anchor
不要忘記將“YOUR-PATH-TO-CHROMEDRIVER”替換為您提取 chromedriver 的位置。此外,您應該注意到page.content,當我們創建 BeautifulSoup 對象時,我們現在使用的是driver.page_source,它提供頁面的 HTML 內容 。
使用上面的代碼,我們現在可以通過調用每個錨點上的 click 方法來訪問每個電影頁面。
first_link = driver.find_elements_by_css_selector('table tbody tr td.titleColumn a')[0]
first_link.click()
這將模擬點擊第一部電影的鏈接。但是,在這種情況下,我建議您繼續使用driver.get instead. 這是因為click()進入不同頁面后您將無法再使用該方法,因為新頁面沒有指向其他九部電影的鏈接。
因此,單擊列表中的第一個標題后,您需要返回第一頁,然后單擊第二頁,依此類推。這是對性能和時間的浪費。相反,我們將只使用提取的鏈接并一一訪問它們。
對于“肖申克的救贖”,電影頁面將是https://www.imdb.com/title/tt0111161/。我們將從頁面中提取電影的年份和時長,但這次我們將使用 Selenium 的函數而不是 BeautifulSoup 作為示例。在實踐中,您可以使用任何一種,因此請選擇您最喜歡的。
要檢索電影的年份和持續時間,您應該重復我們在電影頁面上執行的第一步。
您會注意到您可以在帶有類ipc-inline-list
(“.ipc-inline-list
”選擇器)的第一個元素中找到所有信息,并且列表中的所有元素都有role屬性值presentation([role=’presentation’]
選擇器)。
from bs4 import BeautifulSoup
from selenium import webdriver
option = webdriver.ChromeOptions()
# I use the following options as my machine is a window subsystem linux.
# I recommend to use the headless option at least, out of the 3
option.add_argument('--headless')
option.add_argument('--no-sandbox')
option.add_argument('--disable-dev-sh-usage')
# Replace YOUR-PATH-TO-CHROMEDRIVER with your chromedriver location
driver = webdriver.Chrome('YOUR-PATH-TO-CHROMEDRIVER', options=option)
page = driver.get('https://www.imdb.com/chart/top/') # Getting page HTML through request
soup = BeautifulSoup(driver.page_source, 'html.parser') # Parsing content using beautifulsoup
totalScrapedInfo = [] # In this list we will save all the information we scrape
links = soup.select("table tbody tr td.titleColumn a") # Selecting all of the anchors with titles
first10 = links[:10] # Keep only the first 10 anchors
for anchor in first10:
driver.get('https://www.imdb.com/' + anchor['href']) # Access the movie’s page
infolist = driver.find_elements_by_css_selector('.ipc-inline-list')[0] # Find the first element with class ‘ipc-inline-list’
informations = infolist.find_elements_by_css_selector("[role='presentation']") # Find all elements with role=’presentation’ from the first element with class ‘ipc-inline-list’
scrapedInfo = {
"title": anchor.text,
"year": informations[0].text,
"duration": informations[2].text,
} # Save all the scraped information in a dictionary
totalScrapedInfo.append(scrapedInfo) # Append the dictionary to the totalScrapedInformation list
print(totalScrapedInfo) # Display the list with all the information we scraped
網絡抓取的下一個重要步驟是提取動態加載的內容。您可以在編輯列表部分的每個電影頁面(例如https://www.imdb.com/title/tt0111161/)上找到此類內容。
如果您在頁面上使用檢查,您會看到您可以找到該部分作為屬性data-testid
設置為的元素firstListCardGroup-editorial
。但是如果你查看頁面源代碼,你不會在任何地方找到這個屬性值。這是因為編輯列表部分是由 IMDB 動態加載的。
在下面的示例中,我們將抓取每部電影的編輯列表,并將其添加到我們當前的總抓取信息結果中。
為此,我們將導入更多包,以便等待我們的動態內容加載。
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
option = webdriver.ChromeOptions()
# I use the following options as my machine is a window subsystem linux.
# I recommend to use the headless option at least, out of the 3
option.add_argument('--headless')
option.add_argument('--no-sandbox')
option.add_argument('--disable-dev-sh-usage')
# Replace YOUR-PATH-TO-CHROMEDRIVER with your chromedriver location
driver = webdriver.Chrome('YOUR-PATH-TO-CHROMEDRIVER', options=option)
page = driver.get('https://www.imdb.com/chart/top/') # Getting page HTML through request
soup = BeautifulSoup(driver.page_source, 'html.parser') # Parsing content using beautifulsoup
totalScrapedInfo = [] # In this list we will save all the information we scrape
links = soup.select("table tbody tr td.titleColumn a") # Selecting all of the anchors with titles
first10 = links[:10] # Keep only the first 10 anchors
for anchor in first10:
driver.get('https://www.imdb.com/' + anchor['href']) # Access the movie’s page
infolist = driver.find_elements_by_css_selector('.ipc-inline-list')[0] # Find the first element with class ‘ipc-inline-list’
informations = infolist.find_elements_by_css_selector("[role='presentation']") # Find all elements with role=’presentation’ from the first element with class ‘ipc-inline-list’
scrapedInfo = {
"title": anchor.text,
"year": informations[0].text,
"duration": informations[2].text,
} # Save all the scraped information in a dictionary
WebDriverWait(driver, 5).until(EC.visibility_of_element_located((By.CSS_SELECTOR, "[data-testid='firstListCardGroup-editorial']"))) # We are waiting for 5 seconds for our element with the attribute data-testid set as `firstListCardGroup-editorial`
listElements = driver.find_elements_by_css_selector("[data-testid='firstListCardGroup-editorial'] .listName") # Extracting the editorial lists elements
listNames = [] # Creating an empty list and then appending only the elements texts
for el in listElements:
listNames.append(el.text)
scrapedInfo['editorial-list'] = listNames # Adding the editorial list names to our scrapedInfo dictionary
totalScrapedInfo.append(scrapedInfo) # Append the dictionary to the totalScrapedInformation list
print(totalScrapedInfo) # Display the list with all the information we scraped
對于前面的示例,您應該獲得以下輸出:
現在我們擁有了所需的所有數據,我們可以將其保存為 .json 或 .csv 文件,以便于閱讀。
為此,我們將只使用 Python 中的 JSON 和 CVS 包并將我們的內容寫入新文件:
import csv
import json
...
file = open('movies.json', mode='w', encoding='utf-8')
file.write(json.dumps(totalScrapedInfo))
writer = csv.writer(open("movies.csv", 'w'))
for movie in totalScrapedInfo:
writer.writerow(movie.values())
雖然到目前為止我們的指南已經足夠先進,可以處理 JavaScript 渲染場景,但在 Selenium 中還有很多東西需要探索。
在本節中,我將分享一些可能會派上用場的提示和技巧。
如果您在短時間內向服務器發送數百個請求的垃圾郵件,很可能在某個時候會出現驗證碼,或者您的 IP 甚至可能被阻止。不幸的是,Python 中沒有解決方法可以避免這種情況。
因此,您應該在每個請求之間放置一些超時間隔,以便流量看起來更自然。
import time
import requests
page = requests.get('https://www.imdb.com/chart/top/') # Getting page HTML through request
time.sleep(30) # Wait 30 seconds
page = requests.get('https://www.imdb.com/') # Getting page HTML through request
由于網站是動態的并且可以隨時更改結構,如果您經常使用相同的網絡抓取工具,錯誤處理可能會派上用場。
try:
WebDriverWait(driver, 5).until(EC.presence_of_element_located((By.CSS_SELECTOR, "your selector")))
break
except TimeoutException:
# If the loading took too long, print message and try again
print("Loading took too much time!")
當您等待一個元素、提取它時,甚至當您只是發出請求時,try and error 語法會很有用。
如果您需要隨時獲取正在抓取的網頁的屏幕截圖,可以使用:
driver.save_screenshot(‘screenshot-file-name.png’)
這有助于在您處理動態加載的內容時進行調試。
到此,相信大家對“怎么使用Python從任何網站抓取數據”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。