【python實現網絡爬蟲(17)】使用正則表達式爬取百度以任意關鍵詞搜索返回結果的數據

1. 爬蟲架構

爲了減少不必要的步驟,直接加載一下爬蟲的基礎架構,如下。注意,一定要填寫自己的headers的內容

import re
import requests
import time

headers = {
    'Cookie': '_ga=GA1.2.1075258978.1586877585; _gid=GA1.2.304073749.1587691875; ',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
} #這裏的cookie和header加上自己瀏覽器的即可

def get_data(url):
    html = requests.get(url,headers)
    if html.status_code == 200:
        print('正在爬取中...')
        time.sleep(2)
        parse_html(html.text)
    else:
        print('Error',url)

def parse_html(text):
	pass
    
if __name__ == '__main__':
	pass

2. 創建分頁url

2.1 網頁url規律查找

這裏假設使用“python”作爲關鍵詞進行搜索,然後習慣的是查看第2、3、4頁,這樣就可以查找url之間的規律了,後面的參數會有很多,只需要選取有效的部分即可,如下

u2 = https://www.baidu.com/s?wd=python&pn=10&oq=python&ie=utf-8
u3 = https://www.baidu.com/s?wd=python&pn=20&oq=python&ie=utf-8
u4 = https://www.baidu.com/s?wd=python&pn=30&oq=python&ie=utf-8
......

2.2 創建接口輸出url測試

一次寫的代碼要有可擴展性,而不是隻針對於具體的內容,最好是保留一個接口,這樣可以使得爬蟲的程序代碼高效,因此需要進行input的輸入,然後對於關鍵詞的解析,存在着中文字符,就需要將其轉化爲可以識別的內容,這裏導入urllib庫中的parse模塊進行關鍵詞的解析,如下。

關於第一條語句的使用,該行代碼的意義是什麼?功能就是將執行區和功能函數區進行分割,創建接口

if __name__ == "__main__" 

一個python的文件有兩種使用的方法,第一是直接作爲腳本執行,第二是import到其他的python腳本中被調用(模塊重用)執行。因此該段代碼的作用就是控制這兩種情況執行代碼的過程,在該行代碼下的代碼只有在第一種情況下(即文件作爲腳本直接執行)纔會被執行,而import到其他腳本中是不會被執行的

也就是該行代碼前面就是導入的庫和相關定義的函數,該行代碼下面就是我們進行的具體賦值和對應的操作

if __name__ == '__main__':
	keyword = parse.quote(input('請輸入要爬取的關鍵詞:'))
	num = eval(input('請輸入要爬取的頁數:'))

	for i in range(0,num):
		url = f'https://www.baidu.com/s?wd={keyword}&pn={i*10}&oq={keyword}&ie=utf-8'
		print(url)
		get_data(url)

→ 輸出的結果爲:(因爲保留的接口,所以可以輸入任何關鍵字,比如以“網易”爲例,搜索前3頁)
在這裏插入圖片描述

3 正則表達式匹配

正則表達式在爬蟲中使用有兩種使用方式,一種是不需要配合bs4直接在源代碼中進行數據的匹配(比如爬取B站彈幕時候獲取cid信息,爬取酷狗音樂中獲取榜單的hash值);還有一種結合bs4進行標籤解析結果輸出後進行復雜字段信息的提取(豆瓣讀書詳細信息介紹,鏈家二手房的詳細信息介紹)

3.1 直接匹配源代碼

這時候就不是進入檢查界面了,而是直接在搜索結果的界面鼠標右鍵,然後在彈出的選項中選擇“查看網頁源代碼”,把要爬取的標題在彈出“源代碼”中進行數據匹配,查看保存需求數據的格式,比如就是以剛剛的搜索python爲例,選擇標題和其對應的url爲獲取對象

流程步驟解析:【複製要爬取的內容】→ 【目標頁面右鍵進入源代碼頁面】→ 【ctrl+f調出查找窗口】→ 【在小窗中粘貼複製的內容】→ 【找到目標數據的格式規律】→ 【使用正則替換掉目標數據】→ 編寫代碼

流程圖解,如下,注意箭頭及對應的標號。
在這裏插入圖片描述
代碼如下:只需要將需要匹配的數據進行正則表達式的替換即可

def parse_html(text):
	# print(text)
	infos = re.findall(r'{"title":"(.*?)","url":"(.*?)"}',text)
	print(infos)

→ 輸出的結果爲:(如果需要分別提取title和url的話,就是列表裏面篩選數據,進行遍歷循環後索引即可)
在這裏插入圖片描述

3.2 配合網頁解析進行結果匹配

這個主要是用在複雜字段,解決疑難問題,這次爬取的內容不適合使用這種方式,原因可以在匹配的過程中感受到,如下

1) 網頁解析

這裏還是以“python”作爲關鍵詞進行搜索結果界面的解析。其中可以發現百度的返回結果中前幾個往往都是廣告內容,後面的纔是我們要搜索而返回的結果
在這裏插入圖片描述
2) 標題解析

這裏只針對需要的數據進行標題信息的獲取(排除廣告),可以發現標題的內容被放置在了em的便籤裏面,而且是被分割了
在這裏插入圖片描述
3) 搜索結果的url解析

要獲取搜索返回結果的url的信息,可以發現這個內容就是在標題信息的上面一行中
在這裏插入圖片描述
代碼如下:(首先是要引入bs4解析頁面,然後找到對應信息所在的標籤,然後使用正則表達式匹配標籤的信息)

def parse_html(text):
	soup = BeautifulSoup(text,'lxml')
	infos = soup.find_all('div',class_='result c-container')
	for info in infos:
		info = info.find('h3').a
		print(info)

→ 輸出的結果爲:(只截取部分,這裏其實可以直接.text就已經完成了標題的獲取,使用a[‘href’]也可以直接獲取url)
在這裏插入圖片描述
這裏要配合着bs4使用,可以直接匹配a標籤中的內容進行數據提取

def parse_html(text):
	soup = BeautifulSoup(text,'lxml')
	infos = soup.find_all('div',class_='result c-container')
	for info in infos:
		info = info.find('h3').a
		title = re.search(r'<em>(.*)</a>',str(info)).group(1).replace('</em>','')
		print(title)
		url = re.search(r'href="(.*?)"',str(info)).group(1)
		print(url)

→ 輸出的結果爲:(可以實現數據的獲取)
在這裏插入圖片描述

4. 小結

通過上面的示例可以發現,直接通過正則表達式匹配源代碼是最爲簡單的方式,其中的問題 難點在於找到存放數據的格式,然後把要爬取的數據換成正則表達式,接着就是不建議完全使用正則表達式去匹配解析後的標籤信息,因爲這一步是屬於重複的工作(這裏只是練習使用正則),在實際的爬蟲過程中,可以使用標籤解析的.text方法獲得文本數據或者a[href]獲取url,儘量直接一步到位就可,不需要再這一步使用正則表達式否則就使得問題複雜化了。

注意:正則表達式與bs4配合使用多發生在標籤解析已經獲得文本之後進行文本的提純,比如提到的豆瓣讀書信息詳情的爬取等(有興趣可以試一下,也可以參考一下博客【python爬蟲專項(14)】正則表達式在爬蟲中的應用

個人經驗是(簡潔性):re+源代碼 > bs4 > bs4+re
個人經驗是(常用性):bs4 > bs4 + re > re + 源代碼

5. 全部代碼

5.1 re + 源代碼

import re
import requests
import time
from bs4 import BeautifulSoup
from urllib import parse

headers = {
    'Cookie': 'BIDUPSID=82508FD9E8C7F366210EB75A638DF308; PSTM=1567074841; ',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
} #這裏的refer,cookie和header加上自己瀏覽器的即可


def get_data(url):
    html = requests.get(url,headers=headers)
    if html.status_code == 200:
        print('正在爬取中...')
        time.sleep(2)
        parse_html(html.text)
    else:
        print('Error',url)

def parse_html(text):
	infos = re.findall(r'{"title":"(.*?)","url":"(.*?)"}',text)
	print(infos)
    
if __name__ == '__main__':
	keyword = parse.quote(input('請輸入要爬取的關鍵詞:'))
	num = eval(input('請輸入要爬取的頁數:'))

	for i in range(0,num):
		url = f'https://www.baidu.com/s?wd={keyword}&pn={i*10}&oq={keyword}&ie=utf-8'
		print(url)
		get_data(url)

5.2 bs4 + re

import re
import requests
import time
from bs4 import BeautifulSoup
from urllib import parse

headers = {
    'Cookie': 'BIDUPSID=82508FD9E8C7F366210EB75A638DF308; PSTM=1567074841; ',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
} #這裏的refer,cookie和header加上自己瀏覽器的即可


def get_data(url):
    html = requests.get(url,headers=headers)
    if html.status_code == 200:
        print('正在爬取中...')
        time.sleep(2)
        parse_html(html.text)
    else:
        print('Error',url)

def parse_html(text):
	# print(text)
	# infos = re.findall(r'{"title":"(.*?)","url":"(.*?)"}',text)
	# print(infos)

	soup = BeautifulSoup(text,'lxml')
	infos = soup.find_all('div',class_='result c-container')
	for info in infos:
		info = info.find('h3').a
		title = re.search(r'<em>(.*)</a>',str(info)).group(1).replace('</em>','')
		print(title)
		url = re.search(r'href="(.*?)"',str(info)).group(1)
		print(url)
    
if __name__ == '__main__':
	keyword = parse.quote(input('請輸入要爬取的關鍵詞:'))
	num = eval(input('請輸入要爬取的頁數:'))

	for i in range(0,num):
		url = f'https://www.baidu.com/s?wd={keyword}&pn={i*10}&oq={keyword}&ie=utf-8'
		print(url)
		get_data(url)

附上多頁爬取數據測試的結果(這裏爬取兩頁,對應兩個正在爬取中…)
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章