
區(qū)塊鏈API推薦,快速開(kāi)發(fā)去中心化應(yīng)用
安裝 Python 后,您需要一個(gè)編寫(xiě) Python 代碼的地方。基本上,您需要一個(gè) IDE。
集成開(kāi)發(fā)環(huán)境 (IDE) 提供了編寫(xiě)、測(cè)試和調(diào)試代碼的工具。一些流行的 Python 開(kāi)發(fā) IDE 是:
歸根結(jié)底,IDE的選擇取決于個(gè)人偏好。以上所有選項(xiàng)都配備了運(yùn)行 Python 代碼的能力,并且可以很好地用于我們的網(wǎng)絡(luò)爬蟲(chóng)目的。因此,請(qǐng)選擇適合您偏好的 IDE。
從本質(zhì)上講,Python 庫(kù)是預(yù)打包函數(shù)和方法的集合,它們?cè)试S你在不需要從頭開(kāi)始編寫(xiě)所有內(nèi)容的情況下執(zhí)行許多操作。庫(kù)是軟件開(kāi)發(fā)不可或缺的一部分。最常用的安裝Python庫(kù)的方式是使用pip,Python的包管理系統(tǒng)。
使用pip安裝庫(kù)非常簡(jiǎn)單:
requests
庫(kù),您可以鍵入 pip install requests
。很簡(jiǎn)單,對(duì)吧?現(xiàn)在您已經(jīng)掌握了必要的基礎(chǔ)知識(shí),讓我們來(lái)了解使Python成為網(wǎng)絡(luò)爬蟲(chóng)如此強(qiáng)大和流行的語(yǔ)言的Python庫(kù)。
要在 Python 中開(kāi)始網(wǎng)頁(yè)抓取,您需要兩個(gè)關(guān)鍵工具:HTTP客戶(hù)端(例如HTTPX)用于請(qǐng)求網(wǎng)頁(yè),以及HTML解析器(如BeautifulSoup)來(lái)提取并理解數(shù)據(jù)。
在這一部分,我們將逐步介紹爬蟲(chóng)過(guò)程,并解釋每一步涉及的技術(shù)。通過(guò)這個(gè)過(guò)程,你將學(xué)會(huì)如何使用BeautifulSoup與HTTPX從Hacker News首頁(yè)的所有文章中提取標(biāo)題、排名和URL。
第一步是向目標(biāo)頁(yè)面發(fā)送請(qǐng)求并檢索其 HTML 內(nèi)容。使用 HTTPX 只需幾行代碼即可完成此操作:
?? 安裝 HTTPX
pip install httpx
運(yùn)行下面的代碼。
import httpx
response = httpx.get('https://news.ycombinator.com')
html = response.text
print(html[:200]) # print first 200 characters of html
這段代碼片段通過(guò)發(fā)送GET請(qǐng)求獲取Hacker News首頁(yè)的HTML內(nèi)容,并將前200個(gè)字符打印出來(lái),以驗(yàn)證是否成功獲取了頁(yè)面的HTML。這是通過(guò)使用httpx.get發(fā)送請(qǐng)求并將HTML內(nèi)容存儲(chǔ)在一個(gè)名為html的變量中來(lái)實(shí)現(xiàn)的。然而,原始的HTML對(duì)人們閱讀并不友好。為了以結(jié)構(gòu)化的形式提取有用的數(shù)據(jù),需要使用BeautifulSoup來(lái)解析這個(gè)HTML。
BeautifulSoup 是一個(gè) Python 庫(kù),可幫助您從 HTML 和 XML 文件中提取數(shù)據(jù)。它對(duì)用戶(hù)友好,非常適合中小型項(xiàng)目,因?yàn)樗O(shè)置快速并且可以有效地解析內(nèi)容。如前所述,BeautifulSoup 通常與 HTTP 請(qǐng)求庫(kù)配對(duì)。就像 HTTPX 一樣。現(xiàn)在,讓我們將所有內(nèi)容結(jié)合起來(lái),以結(jié)構(gòu)化格式從 Hacker News 首頁(yè)上的所有文章中抓取數(shù)據(jù)。
BeautifulSoup + HTTPX 代碼從 Hacker News 首頁(yè)的所有文章中提取標(biāo)題內(nèi)容、排名和 URL:
import httpx
from bs4 import BeautifulSoup
# Function to get HTML content from a URL
def get_html_content(url: str, timeout: int = 10) -> str:
response = httpx.get(url, timeout=timeout)
return str(response.text)
# Function to parse a single article
def parse_article(article) -> dict:
url = article.find(class_='titleline').find('a').get('href')
title = article.find(class_='titleline').get_text()
rank = article.find(class_='rank').get_text().replace('.', '')
return {'url': url, 'title': title, 'rank': rank}
# Function to parse all articles in the HTML content
def parse_html_content(html: str) -> list:
soup = BeautifulSoup(html, features='html.parser')
articles = soup.find_all(class_='athing')
return [parse_article(article) for article in articles]
# Main function to get and parse HTML content
def main() -> None:
html_content = get_html_content('https://news.ycombinator.com')
data = parse_html_content(html_content)
print(data)
if __name__ == '__main__':
main()
# Expected Output:
'''
[
{
"url":"https://ian.sh/tsa",
"title":"Bypassing airport security via SQL injection (ian.sh)",
"rank":"1"
},
{
"url":"https://www.elastic.co/blog/elasticsearch-is-open-source-again",
"title":"Elasticsearch is open source, again (elastic.co)",
"rank":"2"
},
...
{
"url":"https://languagelog.ldc.upenn.edu/nll/?p=73",
"title":"Two Dots Too Many (2008) (upenn.edu)",
"rank":"29"
},
{
"url":"https://collidingscopes.github.io/ascii/",
"title":"Show HN: turn videos into ASCII art (open source, js+canvas) (collidingscopes.github.io)",
"rank":"30"
}
]
'''
上面的代碼包含多個(gè)協(xié)同工作的函數(shù),用于抓取和解析Hacker News的首頁(yè)。首先,它使用httpx獲取HTML內(nèi)容,然后針對(duì)特定的CSS選擇器,使用BeautifulSoup提取每篇文章的標(biāo)題、排名和URL。最后,所有這些邏輯被整合到一個(gè)主函數(shù)中,該函數(shù)將文章的詳細(xì)信息收集到一個(gè)列表中,然后打印出來(lái)。
從 Hacker News 首頁(yè)的 30 篇文章中抓取數(shù)據(jù)后,接下來(lái)是時(shí)候擴(kuò)展你的抓取器,以從所有文章中提取數(shù)據(jù)了。這涉及處理 “分頁(yè)”,這是 Web 抓取中的一個(gè)常見(jiàn)挑戰(zhàn)。為了解決這個(gè)問(wèn)題,您需要瀏覽該網(wǎng)站以了解其分頁(yè)的工作原理,然后相應(yīng)地調(diào)整您的代碼。
下面是 Hacker News 的屏幕截圖,突出顯示了實(shí)現(xiàn)分頁(yè)所需的關(guān)鍵元素。你還會(huì)找到更新后的代碼,從所有頁(yè)面抓取文章。
import httpx
from bs4 import BeautifulSoup
import time
# Function to get HTML content from a URL
def get_html_content(url: str, timeout: int = 10) -> str:
response = httpx.get(url, timeout=timeout)
return str(response.text)
# Function to parse a single article
def parse_article(article) -> dict:
url = article.find(class_='titleline').find('a').get('href')
title = article.find(class_='titleline').get_text()
rank = article.find(class_='rank').get_text(strip=True).replace('.', '')
return {'url': url, 'title': title, 'rank': rank}
# Function to parse all articles in the HTML content
def parse_html_content(html: str) -> list:
soup = BeautifulSoup(html, 'html.parser')
articles = soup.find_all(class_='athing')
return [parse_article(article) for article in articles]
# Main function to get and parse HTML content from all pages
def main() -> None:
base_url = 'https://news.ycombinator.com'
page_number = 1
all_data = []
while True:
url = f'{base_url}/?p={page_number}'
html_content = get_html_content(url)
data = parse_html_content(html_content)
all_data.extend(data)
soup = BeautifulSoup(html_content, 'html.parser')
more_link = soup.select_one('.morelink')
if not more_link:
break
page_number += 1
time.sleep(2) # Adding a 2-second delay between requests
print(all_data)
if __name__ == '__main__':
main()
此代碼擴(kuò)展了用于抓取第一頁(yè)的初始代碼段,并對(duì)函數(shù)進(jìn)行了一些調(diào)整。現(xiàn)在,它通過(guò)循環(huán)遍歷多個(gè)頁(yè)面來(lái)處理這些頁(yè)面,更新URL中的頁(yè)碼,并使用與之前相同的解析函數(shù)。
雖然 BeautifulSoup 和 HTTPX 非常適合抓取靜態(tài)網(wǎng)站,但它們無(wú)法處理通過(guò) JavaScript 加載內(nèi)容的動(dòng)態(tài)網(wǎng)站。
為此,我們使用 Playwright,這是一個(gè)瀏覽器自動(dòng)化庫(kù),可捕獲完全呈現(xiàn)的頁(yè)面,包括動(dòng)態(tài)內(nèi)容。Playwright 之所以有效,是因?yàn)樗刂浦粋€(gè)真實(shí)的 Web 瀏覽器,但它比 BeautifulSoup 更耗費(fèi)資源且速度更慢。因此,請(qǐng)?jiān)诖_實(shí)必要的情況下才使用Playwright,對(duì)于更直接的任務(wù),請(qǐng)堅(jiān)持使用我們之前的解決方案。
?? 安裝
# Install the Playwright package
pip install playwright
# Install the necessary browser binaries (Chromium, Firefox, and WebKit)
playwright install
目標(biāo)是在 MintMobile 的第一頁(yè)上抓取每個(gè)產(chǎn)品的名稱(chēng)、價(jià)格和 URL。以下是使用 Playwright 執(zhí)行此操作的方法:
import asyncio
from playwright.async_api import async_playwright
async def main():
async with async_playwright() as p:
browser = await p.firefox.launch(headless=False)
page = await browser.new_page()
await page.goto("https://phones.mintmobile.com/")
# Create a list to hold the scraped data
data_list = []
# Wait for the products to load
await page.wait_for_selector('ul.products > li')
products = await page.query_selector_all('ul.products > li')
for product in products:
url_element = await product.query_selector('a')
name_element = await product.query_selector('h2')
price_element = await product.query_selector('span.price > span.amount')
if url_element and name_element and price_element:
data = {
"url": await url_element.get_attribute('href'),
"name": await name_element.inner_text(),
"price": await price_element.inner_text()
}
data_list.append(data)
await browser.close()
print(data_list)
asyncio.run(main())
此代碼使用 Playwright 啟動(dòng) Firefox 瀏覽器,導(dǎo)航到 MintMobile 手機(jī)頁(yè)面,然后等待產(chǎn)品加載。產(chǎn)品可見(jiàn)后,它會(huì)選擇頁(yè)面上的所有產(chǎn)品元素并循環(huán)訪問(wèn)它們以提取每個(gè)產(chǎn)品的 URL、名稱(chēng)和價(jià)格。這些細(xì)節(jié)隨后被存儲(chǔ)在一個(gè)名為data_list的列表中。
最后,收集數(shù)據(jù)后,關(guān)閉瀏覽器,并打印抓取的產(chǎn)品詳細(xì)信息列表。
這很好用,但僅僅打印數(shù)據(jù)并不太實(shí)用。接下來(lái),讓我們看看如何將此數(shù)據(jù)保存到 CSV 文件。
在Python中將抓取的數(shù)據(jù)保存到CSV文件相當(dāng)簡(jiǎn)單。只需導(dǎo)入Python內(nèi)置的csv模塊,并使用下面的代碼:
import csv
# Save the data to a CSV file
with open('products.csv', mode='w', newline='') as file:
writer = csv.DictWriter(file, fieldnames=["url", "name", "price"])
writer.writeheader()
writer.writerows(data_list)
這段代碼將抓取的數(shù)據(jù)保存到名為products.csv的CSV文件中。它創(chuàng)建該文件,并使用csv.DictWriter來(lái)寫(xiě)入數(shù)據(jù),其中“url”、“name”和“price”作為列標(biāo)題。writeheader()函數(shù)添加這些標(biāo)題,而writerows(data_list)則將每個(gè)產(chǎn)品的詳細(xì)信息寫(xiě)入文件。
以下是完整代碼的最終版本:
import asyncio
import csv
from playwright.async_api import async_playwright
async def main():
async with async_playwright() as p:
browser = await p.firefox.launch(headless=False)
page = await browser.new_page()
await page.goto("https://phones.mintmobile.com/")
# Create a list to hold the scraped data
data_list = []
# Wait for the products to load
await page.wait_for_selector('ul.products > li')
products = await page.query_selector_all('ul.products > li')
for product in products:
url_element = await product.query_selector('a')
name_element = await product.query_selector('h2')
price_element = await product.query_selector('span.price > span.amount')
if url_element and name_element and price_element:
data = {
"url": await url_element.get_attribute('href'),
"name": await name_element.inner_text(),
"price": await price_element.inner_text()
}
data_list.append(data)
await browser.close()
# Save the data to a CSV file
with open('products.csv', mode='w', newline='') as file:
writer = csv.DictWriter(file, fieldnames=["url", "name", "price"])
writer.writeheader()
writer.writerows(data_list)
asyncio.run(main())
接下來(lái),我們將學(xué)習(xí)如何使用Apify將我們的爬蟲(chóng)部署到云端,以便我們可以配置它們按計(jì)劃運(yùn)行,并使用該平臺(tái)的其他許多功能。
Apify 使用稱(chēng)為 Actors 的無(wú)服務(wù)器云程序,這些程序在 Apify 平臺(tái)上運(yùn)行并執(zhí)行計(jì)算任務(wù)。
為了演示這一點(diǎn),我們將使用 Apify SDK、BeautifulSoup 和 HTTPX 創(chuàng)建一個(gè)開(kāi)發(fā)模板,并調(diào)整生成的樣板代碼以運(yùn)行我們的 BeautifulSoup Hacker News 抓取工具。那么,讓我們開(kāi)始吧。
通過(guò) homebrew
在 macOS(或 Linux)上,您可以通過(guò) Homebrew 包管理器安裝 Apify CLI。
brew install apify/tap/apify-cli
通過(guò) NPM
通過(guò)運(yùn)行以下命令來(lái)安裝或升級(jí) Apify CLI:
npm -g install apify-cli
在計(jì)算機(jī)上安裝 Apify CLI 后,只需在終端中運(yùn)行以下命令即可:
apify create bs4-actor
然后,繼續(xù)選擇Python → BeautifulSoup和HTTPX→安裝模板
這條命令將創(chuàng)建一個(gè)名為bs4-actor的新文件夾,安裝所有必要的依賴(lài)項(xiàng),并生成一段樣板代碼。我們可以使用這段樣板代碼,結(jié)合BeautifulSoup、Requests和Python的Apify SDK來(lái)快速啟動(dòng)我們的開(kāi)發(fā)。
最后,進(jìn)入新創(chuàng)建的文件夾,并使用您喜歡的代碼編輯器打開(kāi)它。在這個(gè)例子中,我使用的是VS Code。
cd bs4-actor
code .
模板已經(jīng)創(chuàng)建了一個(gè)功能齊全的爬蟲(chóng)。如果您想在修改代碼之前嘗試一下,可以使用命令apify run
來(lái)運(yùn)行它。抓取的結(jié)果將被存儲(chǔ)在storage/datasets
目錄下。
太好了!現(xiàn)在我們已經(jīng)熟悉了模板,接下來(lái)讓我們進(jìn)入src/main.py
并修改其中的代碼,以便抓取HackerNews的內(nèi)容。
只需進(jìn)行一些調(diào)整,最終代碼就會(huì)變成這樣:
from bs4 import BeautifulSoup
from httpx import AsyncClient
from apify import Actor
async def main() -> None:
async with Actor:
# Read the Actor input
actor_input = await Actor.get_input() or {}
start_urls = actor_input.get('start_urls')
if not start_urls:
Actor.log.info('No start URLs specified in actor input, exiting...')
await Actor.exit()
# Enqueue the starting URLs in the default request queue
rq = await Actor.open_request_queue()
for start_url in start_urls:
url = start_url.get('url')
Actor.log.info(f'Enqueuing {url} ...')
await rq.add_request({'url': url, 'userData': {'depth': 0}})
# Process the requests in the queue one by one
while request := await rq.fetch_next_request():
url = request['url']
Actor.log.info(f'Scraping {url} ...')
try:
# Fetch the URL using httpx
async with AsyncClient() as client:
response = await client.get(url, follow_redirects=True)
soup = BeautifulSoup(response.content, 'html.parser')
articles = soup.find_all(class_='athing')
for article in articles:
data = {
'URL': article.find(class_='titleline').find('a').get('href'),
'title': article.find(class_='titleline').getText(),
'rank': article.find(class_='rank').getText().replace('.', ''),
}
# Push the extracted data into the default dataset
await Actor.push_data(data)
except:
Actor.log.exception(f'Cannot extract data from {url}.')
finally:
# Mark the request as handled so it's not processed again
await rq.mark_request_as_handled(request)
最后,在您的終端中輸入命令apify run
,您將會(huì)看到存儲(chǔ)中填充了從HackerNews抓取的數(shù)據(jù)。
在我們進(jìn)行下一步之前,請(qǐng)轉(zhuǎn)到.actor/input_schema.json
文件,并將預(yù)填充的URL更改為https://news.ycombinator.com/news
。當(dāng)我們?cè)贏pify平臺(tái)上運(yùn)行爬蟲(chóng)時(shí),這一點(diǎn)非常重要。
既然我們已經(jīng)確認(rèn)Actor按預(yù)期工作,現(xiàn)在就可以將其部署到Apify平臺(tái)了。要跟隨以下步驟,您需要注冊(cè)一個(gè)免費(fèi)的Apify賬戶(hù)。
一旦您擁有了一個(gè)Apify賬戶(hù),請(qǐng)?jiān)诮K端中運(yùn)行命令apify login
。系統(tǒng)將提示您提供Apify API Token。您可以在Apify控制臺(tái)中的“設(shè)置”→“集成”下找到該Token。
最后一步是運(yùn)行apify push
命令。這將啟動(dòng)Actor的構(gòu)建過(guò)程,幾秒鐘后,您應(yīng)該能夠在Apify控制臺(tái)下的“Actors”→“我的Actors”中看到您新創(chuàng)建的Actor。apify push
太棒了!您的抓取工具已準(zhǔn)備好在 Apify 平臺(tái)上運(yùn)行!只需點(diǎn)擊“開(kāi)始”按鈕,運(yùn)行結(jié)束后,您就可以在“存儲(chǔ)”選項(xiàng)卡中預(yù)覽并以多種格式下載您的數(shù)據(jù)。
總體而言,Python憑借其簡(jiǎn)潔性和強(qiáng)大的庫(kù),是進(jìn)行網(wǎng)絡(luò)爬蟲(chóng)的絕佳選擇。像BeautifulSoup這樣的工具可以輕松抓取靜態(tài)網(wǎng)站,而Playwright則非常適合處理動(dòng)態(tài)內(nèi)容。使用Python進(jìn)行網(wǎng)絡(luò)爬蟲(chóng)不會(huì)出錯(cuò)。
原文鏈接:https://blog.apify.com/web-scraping-python/
對(duì)比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力
一鍵對(duì)比試用API 限時(shí)免費(fèi)