很多人都聽說過爬蟲,我也不例外。曾看到別人編寫的爬蟲程式碼,雖然沒有深入研究,但感覺非常強大。因此,今天我決定從零開始,花費僅5分鐘學習入門爬蟲技術,以後只需輕輕一爬就能檢視所有感興趣的網站內容。廣告?不存在的,因為我看不見。爬蟲只會獲取我感興趣的資訊,不需要的內容對我而言只是一堆程式碼。我們不在乎網站的介面,爬取完資料後只會關注最核心的內容。
在這個過程中,技術方面實際上沒有太多複雜的內容,實際上就是一項耐心細緻的工作。因此才會有那麼多人選擇從事爬蟲兼職工作,因為雖然耗時較長,但技術要求並不是很高。今天學完之後,你就不會像我一樣認為爬蟲很困難了。或許在未來你會需要考慮如何保持會話(session)或者繞過驗證等問題,因為網站越難爬取,說明對方並不希望被爬取。實際上,這部分內容是最具挑戰性的,有機會的話我們可以在以後的學習中深入討論。
今天我們以選擇菜譜為案例,來解決我們在吃飯時所面臨的“吃什麼”的生活難題。
爬蟲解析
爬蟲的工作原理類似於模擬使用者在瀏覽網站時的操作:首先訪問官方網站,檢查是否有需要點選的連結,若有,則繼續點選檢視。當直接發現所需的圖片或文字時,即可進行下載或複製。這種爬蟲的基本架構如圖所示,希望這樣的描述能幫助你更好地理解。
爬網頁HTML
在進行爬蟲工作時,我們通常從第一步開始,即傳送一個HTTP請求以獲取返回的資料。在我們的工作中,通常會請求一個連結以獲取JSON格式的資訊,以便進行業務處理。然而,爬蟲的工作方式略有不同,因為我們需要首先獲取網頁內容,因此這一步通常返回的是HTML頁面。在Python中,有許多請求庫可供選擇,我只舉一個例子作為參考,但你可以根據實際需求選擇其他第三方庫,只要能夠完成任務即可。
在開始爬蟲工作之前,首先需要安裝所需的第三方庫依賴。這部分很簡單,只需根據需要安裝相應的庫即可,沒有太多複雜的步驟。
讓我們不多廢話,直接看下面的程式碼示例:
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)
# 發出請求,獲取html
# 獲取的html內容是位元組,將其轉化為字串
html = urlopen(req)
html_text = bytes.decode(html.read())
print(html_text)
通常情況下,我們可以獲取這個菜譜網頁的完整內容,就像我們在瀏覽器中按下F12檢視的網頁原始碼一樣。
解析元素
最笨的方法是使用字串解析,但由於Python有許多第三方庫可以解決這個問題,因此我們可以使用BeautifulSoup來解析HTML。其他更多的解析方法就不一一介紹了,我們需要用到什麼就去搜尋即可,不需要經常使用的也沒必要死記硬背。
熱搜菜譜
在這裡,讓我們對熱門搜尋中的菜譜進行解析和分析。
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)
# 發出請求,獲取html
# 獲取的html內容是位元組,將其轉化為字串
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函式獲取所有圖片的資訊
index_hotlist = obj.find_all('a',class_='sancan_item')
# 分別列印每個圖片的資訊
for ul in index_hotlist:
for li in ul.find_all('strong',class_='title'):
print(li.get_text())
主要步驟是,首先在上一步中列印出HTML頁面,然後透過肉眼觀察確定所需內容位於哪個元素下,接著利用BeautifulSoup定位該元素並提取出所需資訊。在我的情況下,我提取的是文字內容,因此成功提取了所有li列表元素。
隨機乾飯
在生活中,實際上乾飯並不複雜,難點在於選擇吃什麼。因此,我們可以將所有菜譜解析並儲存在一個列表中,然後讓程式隨機選擇菜譜。這樣,就能更輕鬆地解決每頓飯吃什麼的難題了。
隨機選取一道菜時,可以使用以下示例程式碼:
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內容是位元組,將其轉化為字串
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'))
這裡我們在這個網站上找到了新的連結地址,我已經獲取了前三頁的資料,並進行了隨機選擇,你可以選擇全部獲取。
菜譜教程
其實上一步已經完成了,接下來只需下單外賣了。外賣種類繁多,但對於像我這樣的顧家奶爸來說並不合適,因此我必須自己動手做飯。這時候教程就顯得尤為重要了。
我們現在繼續深入解析教程內容:
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內容是位元組,將其轉化為字串
html_text = bytes.decode(html.read())
obj = bf(html_text,'html.parser')
index_hotlist = obj.find_all('a',class_='img')
# 分別列印每個圖片的資訊
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())
包裝一下
上面提到的方法已經滿足了我們的需求,但是重複手動執行每個步驟並不是一個高效的方式。因此,我將這些步驟封裝成一個簡單的應用程式。這個應用程式使用控制檯作為使用者介面,不需要依賴任何第三方庫。讓我們一起來看一下這個應用程式吧:
# 匯入urllib庫的urlopen函式
from urllib.request import urlopen,Request
import urllib,string
# 匯入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)
# 發出請求,獲取html
# 獲取的html內容是位元組,將其轉化為字串
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:隨機選擇',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函式獲取所有圖片的資訊
index_hotlist = obj.find_all('a',class_='sancan_item')
# 分別列印每個圖片的資訊
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('正在搜尋詳細教程,請稍等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內容是位元組,將其轉化為字串
html_text = bytes.decode(html.read())
obj = bf(html_text,'html.parser')
index_hotlist = obj.find_all('a',class_='img')
# 分別列印每個圖片的資訊
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內容是位元組,將其轉化為字串
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'隨機選擇,今天吃:{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:代表清空控制檯',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': ## 鍵盤‘Q’是退出
break
if move == 'c': ## 鍵盤‘C’是清空控制檯
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 : ## 鍵盤‘D’是檢視教程
search_food_detail(my_food)
my_food = ''
完成一個簡單的小爬蟲其實並不複雜,如果不考慮額外的封裝步驟,僅需5分鐘即可完成,這已經足夠快速讓你入門爬蟲技術。開始爬取某個網站的資料實際上是一項細緻的工作。只需在網上搜尋相關技術資訊,找到適合的方法即可,如果有效就繼續使用,不行就試試其他方法。
總結
本文的重點在於引導讀者如何初步掌握爬蟲技術。初步掌握爬蟲技術並不難,但是在實際操作中可能會遇到一些困難,比如一些網站不允許直接訪問,需要登入或者進行各種人機驗證等。因此,最好先從爬取一些新聞資訊類的網站開始,因為這樣相對容易。涉及使用者支付等敏感資訊的網站就不那麼容易獲取了。因此,在入門階段,建議不要糾結於選擇一個複雜的網站,先嚐試入門即可。一旦理解了基本原理,遇到問題時就可以考慮新增元件或者使用第三方庫來解決。
最終,我真誠地希望本文對你有所幫助。如果你覺得內容有趣或有用,不妨動動小手,點個關注支援一下,嘻嘻。