五分鐘上手Python爬蟲(chóng):從干飯開(kāi)始,輕松掌握技巧
在這個(gè)過(guò)程中,技術(shù)方面實(shí)際上沒(méi)有太多復(fù)雜的內(nèi)容,實(shí)際上就是一項(xiàng)耐心細(xì)致的工作。因此才會(huì)有那么多人選擇從事爬蟲(chóng)兼職工作,因?yàn)殡m然耗時(shí)較長(zhǎng),但技術(shù)要求并不是很高。今天學(xué)完之后,你就不會(huì)像我一樣認(rèn)為爬蟲(chóng)很困難了。或許在未來(lái)你會(huì)需要考慮如何保持會(huì)話(session)或者繞過(guò)驗(yàn)證等問(wèn)題,因?yàn)榫W(wǎng)站越難爬取,說(shuō)明對(duì)方并不希望被爬取。實(shí)際上,這部分內(nèi)容是最具挑戰(zhàn)性的,有機(jī)會(huì)的話我們可以在以后的學(xué)習(xí)中深入討論。
今天我們以選擇菜譜為案例,來(lái)解決我們?cè)诔燥垥r(shí)所面臨的“吃什么”的生活難題。
爬蟲(chóng)解析
爬蟲(chóng)的工作原理類似于模擬用戶在瀏覽網(wǎng)站時(shí)的操作:首先訪問(wèn)官方網(wǎng)站,檢查是否有需要點(diǎn)擊的鏈接,若有,則繼續(xù)點(diǎn)擊查看。當(dāng)直接發(fā)現(xiàn)所需的圖片或文字時(shí),即可進(jìn)行下載或復(fù)制。這種爬蟲(chóng)的基本架構(gòu)如圖所示,希望這樣的描述能幫助你更好地理解。
image
爬網(wǎng)頁(yè)HTML
在進(jìn)行爬蟲(chóng)工作時(shí),我們通常從第一步開(kāi)始,即發(fā)送一個(gè)HTTP請(qǐng)求以獲取返回的數(shù)據(jù)。在我們的工作中,通常會(huì)請(qǐng)求一個(gè)鏈接以獲取JSON格式的信息,以便進(jìn)行業(yè)務(wù)處理。然而,爬蟲(chóng)的工作方式略有不同,因?yàn)槲覀冃枰紫全@取網(wǎng)頁(yè)內(nèi)容,因此這一步通常返回的是HTML頁(yè)面。在Python中,有許多請(qǐng)求庫(kù)可供選擇,我只舉一個(gè)例子作為參考,但你可以根據(jù)實(shí)際需求選擇其他第三方庫(kù),只要能夠完成任務(wù)即可。
在開(kāi)始爬蟲(chóng)工作之前,首先需要安裝所需的第三方庫(kù)依賴。這部分很簡(jiǎn)單,只需根據(jù)需要安裝相應(yīng)的庫(kù)即可,沒(méi)有太多復(fù)雜的步驟。
讓我們不多廢話,直接看下面的代碼示例:
from urllib.request import urlopen,Request
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0'}
req = Request("https://www.meishij.net/?from=space_block",headers=headers)
# 發(fā)出請(qǐng)求,獲取html
# 獲取的html內(nèi)容是字節(jié),將其轉(zhuǎn)化為字符串
html = urlopen(req)
html_text = bytes.decode(html.read())
print(html_text)
通常情況下,我們可以獲取這個(gè)菜譜網(wǎng)頁(yè)的完整內(nèi)容,就像我們?cè)跒g覽器中按下F12查看的網(wǎng)頁(yè)源代碼一樣。
解析元素
最笨的方法是使用字符串解析,但由于Python有許多第三方庫(kù)可以解決這個(gè)問(wèn)題,因此我們可以使用BeautifulSoup來(lái)解析HTML。其他更多的解析方法就不一一介紹了,我們需要用到什么就去搜索即可,不需要經(jīng)常使用的也沒(méi)必要死記硬背。
熱搜菜譜
在這里,讓我們對(duì)熱門(mén)搜索中的菜譜進(jìn)行解析和分析。
from urllib.request import urlopen,Request
from bs4 import BeautifulSoup as bf
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0'}
req = Request("https://www.meishij.net/?from=space_block",headers=headers)
# 發(fā)出請(qǐng)求,獲取html
# 獲取的html內(nèi)容是字節(jié),將其轉(zhuǎn)化為字符串
html = urlopen(req)
html_text = bytes.decode(html.read())
# print(html_text)
# 用BeautifulSoup解析html
obj = bf(html_text,'html.parser')
# print(html_text)
# 使用find_all函數(shù)獲取所有圖片的信息
index_hotlist = obj.find_all('a',class_='sancan_item')
# 分別打印每個(gè)圖片的信息
for ul in index_hotlist:
for li in ul.find_all('strong',class_='title'):
print(li.get_text())
主要步驟是,首先在上一步中打印出HTML頁(yè)面,然后通過(guò)肉眼觀察確定所需內(nèi)容位于哪個(gè)元素下,接著利用BeautifulSoup定位該元素并提取出所需信息。在我的情況下,我提取的是文字內(nèi)容,因此成功提取了所有l(wèi)i列表元素。
隨機(jī)干飯
在生活中,實(shí)際上干飯并不復(fù)雜,難點(diǎn)在于選擇吃什么。因此,我們可以將所有菜譜解析并存儲(chǔ)在一個(gè)列表中,然后讓程序隨機(jī)選擇菜譜。這樣,就能更輕松地解決每頓飯吃什么的難題了。
隨機(jī)選取一道菜時(shí),可以使用以下示例代碼:
from urllib.request import urlopen,Request
from bs4 import BeautifulSoup as bf
for i in range(3):
url = f"https://www.meishij.net/chufang/diy/jiangchangcaipu/?&page={i}"
html = urlopen(url)
# 獲取的html內(nèi)容是字節(jié),將其轉(zhuǎn)化為字符串
html_text = bytes.decode(html.read())
# print(html_text)
obj = bf(html_text,'html.parser')
index_hotlist = obj.find_all('img')
for p in index_hotlist:
if p.get('alt'):
print(p.get('alt'))
這里我們?cè)谶@個(gè)網(wǎng)站上找到了新的鏈接地址,我已經(jīng)獲取了前三頁(yè)的數(shù)據(jù),并進(jìn)行了隨機(jī)選擇,你可以選擇全部獲取。
菜譜教程
其實(shí)上一步已經(jīng)完成了,接下來(lái)只需下單外賣了。外賣種類繁多,但對(duì)于像我這樣的顧家奶爸來(lái)說(shuō)并不合適,因此我必須自己動(dòng)手做飯。這時(shí)候教程就顯得尤為重要了。
我們現(xiàn)在繼續(xù)深入解析教程內(nèi)容:
from urllib.request import urlopen,Request
import urllib,string
from bs4 import BeautifulSoup as bf
url = f"https://so.meishij.net/index.php?q=紅燒排骨"
url = urllib.parse.quote(url, safe=string.printable)
html = urlopen(url)
# 獲取的html內(nèi)容是字節(jié),將其轉(zhuǎn)化為字符串
html_text = bytes.decode(html.read())
obj = bf(html_text,'html.parser')
index_hotlist = obj.find_all('a',class_='img')
# 分別打印每個(gè)圖片的信息
url = index_hotlist[0].get('href')
html = urlopen(url)
html_text = bytes.decode(html.read())
obj = bf(html_text,'html.parser')
index_hotlist = obj.find_all('div',class_='step_content')
for div in index_hotlist:
for p in div.find_all('p'):
print(p.get_text())
包裝一下
上面提到的方法已經(jīng)滿足了我們的需求,但是重復(fù)手動(dòng)執(zhí)行每個(gè)步驟并不是一個(gè)高效的方式。因此,我將這些步驟封裝成一個(gè)簡(jiǎn)單的應(yīng)用程序。這個(gè)應(yīng)用程序使用控制臺(tái)作為用戶界面,不需要依賴任何第三方庫(kù)。讓我們一起來(lái)看一下這個(gè)應(yīng)用程序吧:
# 導(dǎo)入urllib庫(kù)的urlopen函數(shù)
from urllib.request import urlopen,Request
import urllib,string
# 導(dǎo)入BeautifulSoup
from bs4 import BeautifulSoup as bf
from random import choice,sample
from colorama import init
from os import system
from termcolor import colored
from readchar import readkey
FGS = ['green', 'yellow', 'blue', 'cyan', 'magenta', 'red']
print(colored('搜索食譜中.....',choice(FGS)))
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0'}
req = Request("https://www.meishij.net/?from=space_block",headers=headers)
# 發(fā)出請(qǐng)求,獲取html
# 獲取的html內(nèi)容是字節(jié),將其轉(zhuǎn)化為字符串
html = urlopen(req)
html_text = bytes.decode(html.read())
hot_list = []
all_food = []
food_page = 3
# '\n'.join(pos(y, OFFSET[1]) + ' '.join(color(i) for i in l)
def draw_menu(menu_list):
clear()
for idx,i in enumerate(menu_list):
print(colored(f'{idx}:{i}',choice(FGS)))
print(colored('8:隨機(jī)選擇',choice(FGS)))
def draw_word(word_list):
clear()
for i in word_list:
print(colored(i,choice(FGS)))
def clear():
system("CLS")
def hot_list_func() :
global html_text
# 用BeautifulSoup解析html
obj = bf(html_text,'html.parser')
# print(html_text)
# 使用find_all函數(shù)獲取所有圖片的信息
index_hotlist = obj.find_all('a',class_='sancan_item')
# 分別打印每個(gè)圖片的信息
for ul in index_hotlist:
for li in ul.find_all('strong',class_='title'):
hot_list.append(li.get_text())
# print(li.get_text())
def search_food_detail(food) :
print('正在搜索詳細(xì)教程,請(qǐng)稍等30秒左右!')
url = f"https://so.meishij.net/index.php?q={food}"
# print(url)
url = urllib.parse.quote(url, safe=string.printable)
html = urlopen(url)
# 獲取的html內(nèi)容是字節(jié),將其轉(zhuǎn)化為字符串
html_text = bytes.decode(html.read())
obj = bf(html_text,'html.parser')
index_hotlist = obj.find_all('a',class_='img')
# 分別打印每個(gè)圖片的信息
url = index_hotlist[0].get('href')
# print(url)
html = urlopen(url)
html_text = bytes.decode(html.read())
# print(html_text)
obj = bf(html_text,'html.parser')
random_color = choice(FGS)
print(colored(f"{food}做法:",random_color))
index_hotlist = obj.find_all('div',class_='step_content')
# print(index_hotlist)
random_color = choice(FGS)
for div in index_hotlist:
for p in div.find_all('p'):
print(colored(p.get_text(),random_color))
def get_random_food():
global food_page
if not all_food :
for i in range(food_page):
url = f"https://www.meishij.net/chufang/diy/jiangchangcaipu/?&page={i}"
html = urlopen(url)
# 獲取的html內(nèi)容是字節(jié),將其轉(zhuǎn)化為字符串
html_text = bytes.decode(html.read())
# print(html_text)
obj = bf(html_text,'html.parser')
index_hotlist = obj.find_all('img')
for p in index_hotlist:
if p.get('alt'):
all_food.append(p.get('alt'))
my_food = choice(all_food)
print(colored(f'隨機(jī)選擇,今天吃:{my_food}',choice(FGS)))
return my_food
init() ## 命令行輸出彩色文字
hot_list_func()
print(colored('已搜索完畢!',choice(FGS)))
my_array = list(range(0, 9))
my_key = ['q','c','d','m']
my_key.extend(my_array)
print(colored('m:代表今日菜譜',choice(FGS)))
print(colored('c:代表清空控制臺(tái)',choice(FGS)))
print(colored('d:代表菜譜教程',choice(FGS)))
print(colored('q:退出菜譜',choice(FGS)))
print(colored('0~8:選擇菜譜中的菜',choice(FGS)))
while True:
while True:
move = readkey()
if move in my_key or (move.isdigit() and int(move) <= len(random_food)):
break
if move == 'q': ## 鍵盤(pán)‘Q’是退出
break
if move == 'c': ## 鍵盤(pán)‘C’是清空控制臺(tái)
clear()
if move == 'm':
random_food = sample(hot_list,8)
draw_menu(random_food)
if move.isdigit() and int(move) <= len(random_food):
if int(move) == 8:
my_food = get_random_food()
else:
my_food = random_food[int(move)]
print(my_food)
if move == 'd' and my_food : ## 鍵盤(pán)‘D’是查看教程
search_food_detail(my_food)
my_food = ''
完成一個(gè)簡(jiǎn)單的小爬蟲(chóng)其實(shí)并不復(fù)雜,如果不考慮額外的封裝步驟,僅需5分鐘即可完成,這已經(jīng)足夠快速讓你入門(mén)爬蟲(chóng)技術(shù)。開(kāi)始爬取某個(gè)網(wǎng)站的數(shù)據(jù)實(shí)際上是一項(xiàng)細(xì)致的工作。只需在網(wǎng)上搜索相關(guān)技術(shù)信息,找到適合的方法即可,如果有效就繼續(xù)使用,不行就試試其他方法。
總結(jié)
本文的重點(diǎn)在于引導(dǎo)讀者如何初步掌握爬蟲(chóng)技術(shù)。初步掌握爬蟲(chóng)技術(shù)并不難,但是在實(shí)際操作中可能會(huì)遇到一些困難,比如一些網(wǎng)站不允許直接訪問(wèn),需要登錄或者進(jìn)行各種人機(jī)驗(yàn)證等。因此,最好先從爬取一些新聞資訊類的網(wǎng)站開(kāi)始,因?yàn)檫@樣相對(duì)容易。涉及用戶支付等敏感信息的網(wǎng)站就不那么容易獲取了。因此,在入門(mén)階段,建議不要糾結(jié)于選擇一個(gè)復(fù)雜的網(wǎng)站,先嘗試入門(mén)即可。一旦理解了基本原理,遇到問(wèn)題時(shí)就可以考慮添加組件或者使用第三方庫(kù)來(lái)解決。