前面幾篇文章,初步完成了從網絡請求、數據解析、數據存儲的整個過程,完成了一個爬蟲所需的全部功能。但是通過對數據庫中數據的分析會發現數據庫中的元件數量比網站上的元件數量少了很多。前面的實現過程通過解析網頁中的連接來獲取元件詳細信息頁面,解析出相關的數據。在實際頁面中發現有很多的分頁現象,通過前面的方式僅能獲取第一頁的內容,無法獲取第二頁的內容,這就造成無法爬取所有的頁面,最終是獲取到的數據比網站上的實際數據小的多。
在上面的圖片中可以看到數據被分成了很多頁面來顯示,實際點擊下一頁按鈕,發現地址欄的網址沒有發生任何改變,網站使用的 ajax 動態加載技術來實現翻頁,此時無法通過網址來區分各個頁面的內容。爬取這樣的頁面有一定的困難,但在 python 中還是有方法可以解決的,一般情況下我們可以通過以下方法來解決:
- 通過 selenium 來模擬瀏覽器的行爲,從而獲取翻頁的數據。
- 通過分析相應請求,使用 request 來模擬按鍵的點擊效果,從而獲取翻頁數據。
本節主要通過 request 來模擬網頁上的按鈕點擊來實現翻頁。
獲取翻頁請求網址
翻頁請求實際上是一個 post 的過程,我們需要知道 post 的網址及通過 post 請求提交的數據,通過 chrome 瀏覽器的開發者工具來看下如何實現整個過程。
點擊下一頁後在開發者工具中歐可以看到多了一個 list 的請求,我們先來看一下 list 請求的內容。
從 list 請求的內容,可以看出 post 的網址爲
https://list.szlcsc.com/products/list
,提交的數據主要有以下幾個:
'catalogNodeId': '312',
'pageNumber': '2',
'querySortBySign': '0',
'showOutSockProduct': '1'
catalogNodeId 是分類編號這個數字也與我們當前訪問的網址的內容一致https://list.szlcsc.com/catalog/312.html
,pageNumber 是當前的頁碼,其他兩個可以看做是固定值。
使用 request 模擬瀏覽器請求
通過 request 攜帶參數向https://list.szlcsc.com/catalog/312.html
提交數據,來獲取動態翻頁的返回數據,整個代碼試下過程如下:
url = 'https://list.szlcsc.com/products/list'
query = {
'catalogNodeId': '313',
'pageNumber': '325',
'querySortBySign': '0',
'showOutSockProduct': '1'
}
fromData = urllib.parse.urlencode(query).encode('utf-8')
response = request.urlopen(url=url,data=fromData, timeout=10)
html = response.read()
data = dict(json.loads(html.decode('utf-8')))
提交的 fromData 數據需要轉換爲 utf-8 編碼。
獲取到的數據是 json 格式的需要將其轉換爲 python 的字典進行分析。獲取到的數據內容如下:
{
'ICMemberButton': True,
'ICMemberDiscount': '95',
'isCustomerRemindReplenish': False,
'productRecordList':
[
{
'theRatio': 100,
'productArrange': '-',
'productModel': '0402B821J500CT',
'showLastEncaption': True,
'hasSetProduct': None,
'venditionUnit': '個',
'stockNumberWay': 0,
'hasAnnexPCB': 'yes',
'isChooseModel': None,
'discount': None,
'blankBoardId': None,
'productUnit': '個',
'productName': '820pF(821) ±5% 50V ',
'lightCatalogName': '貼片電容',
'numberprices': '個,100,77,1,-1,1,9,0.018156,10,29,0.013408,30,99,0.012536,100,499,0.011664,500,999,0.011276,1000,-1,0.011085',
'bomMainUuid': None,
'spNumber': 1000,
'priceListSize': 6,
'groupCode': '',
...
由於數據太多,這裏僅僅貼出了一部分內容。在這裏我們可以解析出各個元件的 productId,通過該編號組合成完整的網址來獲取該元件的所有信息。代碼如下:
def get_product_item_url(self, current_url):
product_post_url = 'https://list.szlcsc.com/products/list'
query = {
'catalogNodeId': '313',
'pageNumber': '325',
'querySortBySign': '0',
'showOutSockProduct': '1'
}
p1 = re.compile(r'[/]([0-9]*?)[.]', re.S)
category_id = re.findall(p1, current_url)
logger.info(category_id)
page = 0
query['catalogNodeId'] = category_id[0]
query['pageNumber'] = str(page)
while True:
query['pageNumber'] = str(page)
date = urllib.parse.urlencode(query).encode('utf-8')
try:
response = request.urlopen(url=product_post_url,data=date, timeout=10)
html = response.read()
except BaseException as e:
logger.error(2)
return
data = dict(json.loads(html.decode('utf-8')))
productRecordList = data.get('productRecordList')
if not productRecordList:
break
for product in productRecordList:
item_id = product.get('productId')
if item_id:
item_url = 'https://item.szlcsc.com/' + item_id + '.html'
if item_url not in self.bloomfilter:
self.bloomfilter.add(item_url)
self.__url_queue.put(item_url)
page = page + 1
以上代碼通過類似 https://list.szlcsc.com/catalog/312.html
的網址解析出該頁面所有的 productId,並拼接成完整的產品鏈接,將鏈接放入待爬隊列中。