天天看點

python爬蟲_爬取京東商品寫入Excel表

新人的第二篇文章,寫的不好請見諒

這段代碼隻是針對京東的商品資訊爬取,很多都是根據頁面源碼去比對擷取資料的,别的網站用不了,也可能過一段時間官方修改了頁面就不能用了,不過這裡也隻是提供學習使用,希望可以幫到初學者

這裡附上兩個我學習時用的文章

使用的是requests+BeautifulSoup請求以及解析網頁(本文章所使用的技術)

這個是使用的webdriver,和本文不一樣,有需要的可以看一下

'''
爬取的是京東的8424西瓜的商品資訊
要爬取企業資訊需要驗證碼,要一個一個輸入
若不爬取企業資訊則可以實作自動爬取想要的頁數,請做如下改動
注釋掉97行115行124行132行   打開125行(加了幾行注釋可能行數就變了,不過下面相應的行也會标出注釋)
'''
import re
import xlwt
import time
import requests
from PIL import Image 
from bs4 import BeautifulSoup
#from lxml import etree

item_value = []
count = 1
browser = requests.session()
requestVerifyCodeUrl = "https://mall.jd.com/sys/vc/createVerifyCode.html"
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36'}

def parserUrl(url, params={}):
    #解析URL(要多次請求是以就單獨列出來一個方法)
    global headers
    req = requests.get(url, headers=headers, params=params)#headers一定要有,模拟浏覽器請求,params是參數
    #time.sleep(1)  #貌似不需要1s就可以一直請求京東,淘寶好像就會有驗證
    soup = BeautifulSoup(req.text, "lxml")
    return soup

def enterprisePage(url):
    #處理企業詳情頁面相關資料
    while True:
        global headers
        global requestVerifyCodeUrl
        #這裡不可以用requests.get請求了,因為cookie的緣故,這個是我找到的最簡單的解決辦法了browser = requests.session()就可以自動儲存cookie了
        req = browser.get(requestVerifyCodeUrl, headers=headers)
        #儲存驗證碼圖檔
        f = open("VerifyCodeImage.jpg", 'wb')
        f.write(req.content)
        f.close()
        f1 = open("VerifyCodeImage.jpg", 'rb')
        image = Image.open(f1)
        image.show()
        f1.close()
        #手動輸入
        vc = input('請輸入驗證碼:')#深度學習識别會在後續的文章中給出
        datas = {'verifyCode' : vc}
        #這裡使用browser.post就會和上面請求驗證碼的cookie一緻了
        req2 = browser.post(url, data=datas, headers=headers)
        soup = BeautifulSoup(req2.text, "lxml")
        #判斷若是有form的代碼塊則證明沒有驗證成功,這個就要去網頁源碼中觀察倆個頁面的差異了
        if soup.find('form'):
            print('驗證碼輸入錯誤!請重新輸入!')
            continue
        infoList = soup.find_all('li', attrs={'class':'noBorder'})#擷取企業相關資訊代碼段
        for info in infoList:
            if info.find('label', attrs={'class':'jLabel'}):
                if info.find('label', attrs={'class':'jLabel'}).text == "企業名稱: ":
                    item_value.append(info.find('span').text)#企業名稱
                if info.find('label', attrs={'class':'jLabel'}).text == "公司位址:":
                    item_value.append(info.find('span').text)#企業位址
        return

def itemPage(url):
    #處理商品詳情頁面相關資料
    #淨含量是在清單頁面沒有的是以要進到詳情頁面擷取
    soup = parserUrl(url)
    clearfixList = soup.find_all('dl', attrs={'class':'clearfix'})#擷取重量相關代碼段
    for clearfix in clearfixList:
        if clearfix.find('dt').text == "淨含量":
            weight = re.sub("[a-zA-Z]", "", clearfix.find('dd').text)
            return weight
    return None

def storePage(url):
    #處理店鋪詳情頁面相關資料
    #嚴格來說并沒有進到店鋪頁面,這個頁面沒有什麼要擷取的,但是要從這裡擷取企業頁面于是就中間加了這麼一個函數
    storID = re.sub("[^0-9]", "", url)
    enterpriseUrl = 'https://mall.jd.com/showLicence-' + str(storID) + '.html'
    #本來企業url是在店鋪頁面中爬取的,但是是動态加載的,源碼中是沒有的,但是經過觀察發現這這兩個頁面的url一部分是固定的,
    #隻是更改了店鋪的id,這樣我們就可以拼接出企業url了(曲線救國)
    enterprisePage(enterpriseUrl)

def mainPage(sheet, n):
    #處理搜尋頁面相關資料
    url = "https://search.jd.com/search?"
    #隻要參數這樣設定隻改變n就可以爬取想要的頁數的資料了,不用考慮翻頁和下拉滾動條
    params = {"keyword":"8424西瓜", 'page':str(n), 'scrolling':'y'}
    soup = parserUrl(url, params)
    #下面的相關資訊的擷取都是要求網頁源碼中對應的字段去比對,并不是所有網站通用的
    item_list = soup.find_all("li", attrs={"class":"gl-item"})
    for item in item_list:
        p_name = item.find('div', attrs={"class":"p-name p-name-type-2"})#擷取商品相關代碼段
        itemName = p_name.find('em').text
        itemUrl = 'https:' + p_name.find('a')['href']
        p_price = item.find('div', attrs={"class":"p-price"})#擷取價格相關代碼段
        itemPrice = p_price.find('i').text
        p_shop = item.find('div', attrs={"class":"p-shop"})#擷取店鋪相關代碼段
        storeName = p_shop.find('a').text
        storeUrl = 'https:' + p_shop.find('a')['href']
        
        item_value.clear()
        item_value.append(storeName)#店鋪名字
        item_value.append(storeUrl)#店鋪URL
        item_value.append(itemName)#商品名字
        item_value.append(itemUrl)#商品URl
        storePage(storeUrl)#在店鋪頁面處理資料   不輸入驗證碼注釋掉這一行
        item_value.append(itemPrice)#商品價格
        itemWeight = itemPage(itemUrl)#在商品頁面處理資料
        if itemWeight:
            item_value.append(itemWeight)#商品重量
        else :
            item_value.append(0)
        if itemWeight:
            itemUnitPrice = float(itemPrice) / float(itemWeight) / 2
            item_value.append('%.2f' %itemUnitPrice)#商品單價
        else :
            item_value.append(0)
            
        #寫入excel表
        global count
        for i in range(0, len(item_value)):
            sheet.write(count, i, item_value[i])
        count += 1
        if count == 4: return#不輸入驗證碼注釋掉這一行,數字減一是爬取商品的數目
    if n%2 == 0:
        print("******已完成第" + str(n/2) +"頁商品資訊寫入******")

def main():
    n = input("請輸入要爬取的頁數:")
    n = int(n) * 2
    print("**************正在寫入**************")
    print("請稍候...")
    value_title = ['店鋪名稱','店鋪URL','商品名稱','商品URL','企業名稱','企業位址','價格(元)','重量(kg)','單價(元/500g)']#不輸入驗證碼注釋掉這一行并且打開下一行
    #value_title = ['店鋪名稱','店鋪URL','商品名稱','商品URL','價格(元)','重量(kg)','單價(元/500g)']
    workbook = xlwt.Workbook()
    sheet = workbook.add_sheet('8424西瓜')
    for i in range(0, len(value_title)):
        sheet.write(0, i, value_title[i])#寫入表頭
    '''    
    這裡要說明一下京東的搜尋頁面最開始是隻加載一半的,當下拉滾動條會加載剩下的一半,又發現url中的參數page=1當點選下一頁page=3,
    會這樣每次+2,通過下拉滾動條加載後半頁抓包可見頁面是發送了一個請求的,這個請求的網址的page參數是2,4,6雙數的,
    不難發現隻要n++就可以一個不漏的爬取所有資訊了,不需要什麼模拟下拉滾動條和翻頁,是以要爬取1頁page=1-2,爬取2頁page=1-4,爬取3頁page=1-6,
    不要習慣的從0開始哈
    '''
    for i in range(1, n+1):
        mainPage(sheet, i)
        break#不輸入驗證碼注釋掉這一行
    workbook.save('京東商品資料.xls')
    print("**************寫入完成**************")

if __name__ == '__main__':
    main()

           

源檔案這裡可以下載下傳,不過也就是一份.py的檔案,就是上面的代碼沒加注釋版。

前人栽樹後人乘涼,乘涼之後也要記得栽樹哦。