【GUI開發案例】用python爬百度搜尋結果,並開發成exe桌面軟體!

2022-11-24 12:01:48

一、背景介紹

你好,我是 @馬哥python說 ,一名10年程式猿。

1.1 老版本

之前我開發過一個百度搜尋的python爬蟲程式碼,具體如下:
【python爬蟲案例】用python爬取百度的搜尋結果!
這個爬蟲程式碼自發布以來,受到了眾多小夥伴的關注:

但是,很多不懂python程式設計的小夥伴無法使用它,非常痛苦!

於是,我把這個程式封裝成了一個桌面軟體(exe檔案),無需python執行環境也可以使用。

1.2 爬取目標

1.3 軟體執行截圖

1.4 爬取資料

1.5 實現思路

通過python爬蟲技術,爬取百度搜尋結果資料,包含欄位:

頁碼、標題、百度連結、真實連結、簡介、網站名稱。

並把原始碼封裝成exe檔案,方便沒有python環境,或者不懂技術的人使用它。

二、程式碼講解

2.1 爬蟲

首先,匯入需要用到的庫:

import requests  # 傳送請求
from bs4 import BeautifulSoup  # 解析頁面
import pandas as pd  # 存入csv資料
import os  # 判斷檔案存在
from time import sleep  # 等待間隔
import random  # 隨機
import re  # 用正規表示式提取url

定義一個請求頭:

# 偽裝瀏覽器請求頭
headers = {
	"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36",
	"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
	"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
	"Connection": "keep-alive",
	"Accept-Encoding": "gzip, deflate, br",
	"Host": "www.baidu.com",
	# 需要更換Cookie
	"Cookie": "換成自己的cookie"
}

Cookie是個關鍵,如果不加Cookie,響應碼可能不是200,獲取不到資料,而且Cookie值是有有效期的,需要定期更換,如果發現返回無資料或響應碼非200,嘗試替換最新的Cookie。

怎麼獲取到Cookie呢?開啟Chrome瀏覽器,存取百度頁面,按F12進入開發者模式:

按照圖示順序,依次:

  1. 點選Network,進入網路頁
  2. 點選All,檢視所有網路請求
  3. 選擇目標連結,和位址列裡的地址一致
  4. 檢視Request Headers請求頭
  5. 檢視請求頭裡的Cookie,直接右鍵,Copy value,貼上到程式碼裡

然後,分析頁面請求地址:

wd=後面是搜尋鍵碼"馬哥python說",pn=後面是10(規律:第一頁是0,第二頁是10,第三頁是20,以此類推),其他URL引數可以忽略。

然後,分析頁面元素,以搜尋結果標題為例:

每一條搜尋結果,都是class="result c-container new-pmd",下層結構裡有簡介、連結等內容,解析內部子元素不再贅述。

所以根據這個邏輯,開發爬蟲程式碼。

# 獲得每頁搜尋結果
for page in range(v_max_page):
	print('開始爬取第{}頁'.format(page + 1))
	wait_seconds = random.uniform(1, 2)  # 等待時長秒
	print('開始等待{}秒'.format(wait_seconds))
	sleep(wait_seconds)  # 隨機等待
	url = 'https://www.baidu.com/s?wd=' + v_keyword + '&pn=' + str(page * 10)
	r = requests.get(url, headers=headers)
	html = r.text
	print('響應碼是:{}'.format(r.status_code))
	soup = BeautifulSoup(html, 'html.parser')
	result_list = soup.find_all(class_='result c-container new-pmd')
	print('正在爬取:{},共查詢到{}個結果'.format(url, len(result_list)))

其中,獲取到的標題連結,一般是這種結構:

http://www.baidu.com/link?url=7sxpKz_qoESU5b1BHZThKRAnXxPngB5kx1nZdUBCaXh7a4BgUgx9Zz-IqpeqDZTOIjvfY0u6ebnJdVWIfm5Tz_

這顯然是百度的一個跳轉前的地址,不是目標地址,怎麼獲取它背後的真實地址呢?

向這個跳轉前地址,傳送一個請求,然後邏輯處理下:

def get_real_url(v_url):
	"""
	獲取百度連結真實地址
	:param v_url: 百度連結地址
	:return: 真實地址
	"""
	r = requests.get(v_url, headers=headers, allow_redirects=False)  # 不允許重定向
	if r.status_code == 302:  # 如果返回302,就從響應頭獲取真實地址
		real_url = r.headers.get('Location')
	else:  # 否則從返回內容中用正規表示式提取出來真實地址
		real_url = re.findall("URL='(.*?)'", r.text)[0]
	print('real_url is:', real_url)
	return real_url

如果響應碼是302,就從響應頭中的Location引數獲取真實地址。

如果是其他響應碼,就從響應內容中用正規表示式提取出URL真實地址。

把爬取到的資料,儲存到csv檔案:

df = pd.DataFrame(
			{
				'關鍵詞': kw_list,
				'頁碼': page_list,
				'標題': title_list,
				'百度連結': href_list,
				'真實連結': real_url_list,
				'簡介': desc_list,
				'網站名稱': site_list,
			}
		)
if os.path.exists(v_result_file):
	header = None
else:
	header = ['關鍵詞', '頁碼', '標題', '百度連結', '真實連結', '簡介', '網站名稱']  # csv檔案檔頭
df.to_csv(v_result_file, mode='a+', index=False, header=header, encoding='utf_8_sig')
print('結果儲存成功:{}'.format(v_result_file))

to_csv的時候需加上選項(encoding='utf_8_sig'),否則存入資料會產生亂碼,尤其是windows使用者!

2.2 軟體介面

介面部分程式碼:

# 建立主視窗
root = tk.Tk()
root.title('百度搜尋爬蟲-客製化化開發 | 馬哥python說')
# 設定視窗大小
root.minsize(width=850, height=650)

show_list_Frame = tk.Frame(width=800, height=450)  # 建立<訊息列表分割區>
show_list_Frame.pack_propagate(0)
show_list_Frame.place(x=30, y=120, anchor='nw')  # 擺放位置

# 卷軸
scroll = tk.Scrollbar(show_list_Frame)
# 放到Y軸豎直方向
scroll.pack(side=tk.RIGHT, fill=tk.Y)

2.3 紀錄檔模組

軟體執行過程中,會在同級目錄下生成logs資料夾,資料夾內會出現log檔案,記錄下軟體在整個執行過程中的紀錄檔,方便長時間執行、無人值守,出現問題後的debug。

部分核心程式碼:

class Log_week():
    def get_logger(self):
        self.logger = logging.getLogger(__name__)
        # 紀錄檔格式
        formatter = '[%(asctime)s-%(filename)s][%(funcName)s-%(lineno)d]--%(message)s'
        # 紀錄檔級別
        self.logger.setLevel(logging.DEBUG)
        # 控制檯紀錄檔
        sh = logging.StreamHandler()
        log_formatter = logging.Formatter(formatter, datefmt='%Y-%m-%d %H:%M:%S')
        # info紀錄檔檔名
        info_file_name = time.strftime("%Y-%m-%d") + '.log'
        # 將其儲存到特定目錄,ap方法就是尋找專案根目錄,該方法博主前期已經寫好。
        case_dir = r'./logs/'
        info_handler = TimedRotatingFileHandler(filename=case_dir + info_file_name,
                                                when='MIDNIGHT',
                                                interval=1,
                                                backupCount=7,
                                                encoding='utf-8')
        self.logger.addHandler(sh)
        sh.setFormatter(log_formatter)
        self.logger.addHandler(info_handler)
        info_handler.setFormatter(log_formatter)
        return self.logger

三、軟體執行演示

演示視訊:
【爬蟲GUI演示】用python爬百度搜尋,並開發成exe桌面軟體!


我是 @馬哥python說,持續分享python乾貨!