利用Python爬取京東商品的一種辦法
前言
如今的京東、淘寶、天貓等等已經不同往日了, 在使用者不登入的情況下, 很難通過技術手段來大規模獲取到我們關注的商品資訊. 關於京東等購物網站的自動登入也有很多人在做, 但是大廠的反爬能力確實很強, 目前能查閱到的自動登入技術基本都過時了. 本文乾脆跳過這一過程, 換一個思路.
在不登入的情況下獲取商品的編號
我們登入京東的網址jd.com後可以在不登入的情況下直接搜尋商品, 比如搜尋手機
可以看到, 其實這一頁面就已經列出商品的名稱, 售價, 評價量等等. 遺憾的是這個頁面的內容不能直接爬取, 但是我們點開其中一個商品, 並找到它的商品介紹
不難發現, 不同的裝置在型號、引數、效能上可能會存在著重複,但是在京東商城的商品編號是唯一的, 更方便的一點是, 商品編號就是這一商品的url. 例如上述小米手機的地址為https://item.jd.com/100009082500.html
我們開啟開發者工具, 選擇Network, 可以很容易的發現一條資訊, productcommentsummaries, 那麼它很有可能會包含商品的編號.
進一步開啟它可以發現有很多數字串, 其實這些就是在keyword=手機條件下的商品編號, 如果我們需要大規模爬取, 可以手動多點幾頁, 就獲取很多這樣的內容. 為進行測試, 本文截取了少量編號
一旦獲取了商品編號, 那麼商品的資訊就很好獲取了, 假如我們想要獲取某一款手機的詳細配置, 如下圖
可以嘗試如下的程式碼, 先通過簡單的讀取txt檔案將單一的商品編號轉變為可訪問的url
import csv
import pandas as pd
import time
import os
import requests
from bs4 import BeautifulSoup
def get_url(dir):
commo_list = []
List = []
col = 0
with open(dir,"r") as f:
for line in f.readlines():
line = line.strip("\n")
List = list(eval(line))
col = col + 1
print("第{0}行".format(col))
for i in range(len(List)):
commo_list.append(List[i])
print(line)
print("---商品編號總計:{0}個---".format(len(commo_list)))
return commo_list
dir = 'D:/Desktop/commodity.txt'
commodity_list = get_url(dir)
結果如下
通過request庫來獲取url
def get_page(commo):
page_list = []
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 \
(KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36'
} #定義頭部
#https://item.jd.com/100014589194.html http example
#for i in range(len(commo)): #設定爬取量
for i in range(10): #為提高效率, 本示例中僅爬取10個商品
url = "https://item.jd.com/" + str(commo[i]) + ".html"
page = requests.get(url,headers=headers)
print("第{0}個頁面狀態碼:{1}".format(i,page.status_code))
time.sleep(1.5) #程式掛起, 防止反爬蟲
#page = requests.get()
page_list.append(page)
print("獲取完畢")
return page_list
#Page = get_page(commodity_list)
在程式碼執行的過程中加入頁面的狀態碼, 這樣可以很快的向我們反映哪些地址被成功訪問了, 而哪些沒有. 同時引入time.sleep()函式能夠有效的防止因訪問過快而被封ip. 執行結果如下
通過簡單的檢視手機相信相信頁的標籤結果, 很容易能發現這些有價值的資訊都被存在div:class=Ptable-item標籤中
用BeautifulSoup庫解析頁面
def analysis_page(analysis, head):
Soup = []
Dt = []
Dd = []
Div = []
Dl = []
DD = []
DT = []
pro = 1
for i in range(len(analysis)):
soup = BeautifulSoup(analysis[i].text,"html.parser")
#print(soup)
div = soup.find_all('div',attrs={"class":['Ptable-item']}) #返回div為列表
print(div)
Dt = []
Dd = []
for ll in div:
dl = ll.find_all('dl',{'class':['clearfix']})
for i in range(len(dl)):
if dl[i].dd.attrs == {'class': ['Ptable-tips']}:
#print(dl[i].dt.text, ":", dl[i].dd.next_sibling.next_sibling.string)
Dt.append(dl[i].dt.text)
Dd.append(dl[i].dd.next_sibling.next_sibling.string)
else:
#print(dl[i].dt.string, ":", dl[i].dd.string)
Dt.append(dl[i].dt.string)
Dd.append(dl[i].dd.string)
DT.append(Dt)
DD.append(Dd)
print("\r" + "{0:.2f}".format(pro/len(analysis)),end = "")
pro = pro + 1
return Dl, DT, DD
result = analysis_page(Page, 2)
這樣, div標籤中的資訊就被儲存到result中了, 我們來檢視一下
商品資訊顯示正常沒有亂碼, 也沒有冗餘資訊
儲存為CSV格式
df = pd.DataFrame(result[2])
df.replace("\n",'',inplace=True,regex=True)
df.to_csv("D://Desktop/result2.csv")
但從儲存的結果來看, 似乎程式的輸出是正常的, 但csv檔案卻顯示不正常
可以通過如下辦法解決:
1.用記事本開啟
2.另存為帶有BOM的UTF-8檔案
3. 再次開啟csv檔案
可以看到中文顯示正常了, 但其中穿插著很多的空行. 解決辦法:選中第一列後點擊篩選
只選中空白行
此時可以看到空白行已經用藍色標識出, 將其刪除即可
一些思考
實際上, 本文的程式碼效率並不高, 再加上反爬蟲需要對程式掛起就更消耗時間和記憶體, 還需要進一步考慮多執行緒爬蟲和提高程式碼效率.