使用Python 爬取 京東 ,淘寶。 商品詳情頁的數據。(避開了反爬蟲機制)

  • 2022 年 1 月 10 日
  • 筆記

以下是爬取京東商品詳情的Python3程式碼,以excel存放鏈接的方式批量爬取。excel如下

 

程式碼如下

from selenium import webdriver
from lxml import etree
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import datetime
import calendar
import logging
from logging import handlers
import requests
import os
import time
import pymssql
import openpyxl
import xlrd
import codecs



class EgongYePing:

     options = webdriver.FirefoxOptions()
     fp = webdriver.FirefoxProfile()
     fp.set_preference("browser.download.folderList",2)  
     fp.set_preference("browser.download.manager.showWhenStarting",False)
     fp.set_preference("browser.helperApps.neverAsk.saveToDisk","application/zip,application/octet-stream")
     global driver 
     driver= webdriver.Firefox(firefox_profile=fp,options=options)
     def Init(self,url,code):
                       print(url.strip())
                       driver.get(url.strip())
                       #driver.refresh()
                       # 操作瀏覽器屬於非同步,在網路出現問題的時候。可能程式碼先執行。但是請求頁面沒有應答。所以硬等
                       time.sleep(int(3))
                       html = etree.HTML(driver.page_source) 
                       if driver.title!=None:
                         listImg=html.xpath('//*[contains(@class,"spec-list")]//ul//li//img')
                         if len(listImg)==0:
                              pass
                         if len(listImg)>0:
                                            imgSrc=''
                                            for item in range(len(listImg)):    
                                                 imgSrc='//img14.360buyimg.com/n0/'+listImg[item].attrib["data-url"]
                                                 print('頭圖下載:'+imgSrc)
                                                 try:
                                                  Headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0'}
                                                  r = requests.get(imgSrc, headers=Headers, stream=True)
                                                  if r.status_code == 200:
                                                     imgUrl=''
                                                     if item==0:
                                                          imgUrl+=code + "_主圖_" + str(item)  + '.' + imgSrc.split('//')[1].split('/')[len(imgSrc.split('//')[1].split('/'))-1].split('.')[1]
                                                     else:
                                                          imgUrl+=code + "_附圖_" + str(item)  + '.' + imgSrc.split('//')[1].split('/')[len(imgSrc.split('//')[1].split('/'))-1].split('.')[1]
                                                     open(os.getcwd()+'/img/'+  imgUrl , 'wb').write(r.content) # 將內容寫入圖片
                                                  del r
                                                 except Exception as e:
                                                    print("圖片禁止訪問:"+imgSrc) 
                         listImg=html.xpath('//*[contains(@class,"ssd-module")]') 
                         if len(listImg)==0:
                              listImg=html.xpath('//*[contains(@id,"J-detail-content")]//div//div//p//img')
                         if len(listImg)==0:
                              listImg=html.xpath('//*[contains(@id,"J-detail-content")]//img')
                         if len(listImg)>0:
                               for index in range(len(listImg)):  
                                    detailsHTML=listImg[index].attrib
                                    if 'data-id' in detailsHTML:
                                          try:
                                           details= driver.find_element_by_class_name("animate-"+listImg[index].attrib['data-id']).value_of_css_property('background-image')
                                           details=details.replace('url(' , ' ')
                                           details=details.replace(')' , ' ')
                                           newDetails=details.replace('"', ' ')
                                           details=newDetails.strip()
                                           print("詳情圖下載:"+details)
                                           try:
                                                  Headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0'}
                                                  r = requests.get(details, headers=Headers, stream=True)
                                                  if r.status_code == 200:
                                                     imgUrl=''
                                                     imgUrl+=code + "_詳情圖_" + str(index)  + '.' + details.split('//')[1].split('/')[len(details.split('//')[1].split('/'))-1].split('.')[1]
                                                     open(os.getcwd()+'/img/'+   imgUrl, 'wb').write(r.content) # 將內容寫入圖片
                                                  del r
                                           except Exception as e:
                                                    print("圖片禁止訪問:"+details) 
                                          except Exception as e:      
                                               print('其他格式的圖片不收錄');       
                                    if  'src' in detailsHTML:
                                         try:
                                           details= listImg[index].attrib['src']
                                           if 'http' in details:
                                                     pass
                                           else:
                                                     details='https:'+details
                                           print("詳情圖下載:"+details)
                                           try:
                                                  Headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0'}
                                                  r = requests.get(details, headers=Headers, stream=True)
                                                  if r.status_code == 200:
                                                     imgUrl=''
                                                     imgUrl+=code + "_詳情圖_" + str(index)  + '.' + details.split('//')[1].split('/')[len(details.split('//')[1].split('/'))-1].split('.')[1]
                                                     open(os.getcwd()+'/img/'+   imgUrl, 'wb').write(r.content) # 將內容寫入圖片
                                                  del r
                                           except Exception as e:
                                                    print("圖片禁止訪問:"+details) 
                                         except Exception as e:      
                                               print('其他格式的圖片不收錄'); 

                       print('結束執行')

         

     @staticmethod
     def readxlsx(inputText):
        filename=inputText
        inwb = openpyxl.load_workbook(filename)  # 讀文件
        sheetnames = inwb.get_sheet_names()  # 獲取讀文件中所有的sheet,通過名字的方式
        ws = inwb.get_sheet_by_name(sheetnames[0])  # 獲取第一個sheet內容
        # 獲取sheet的最大行數和列數
        rows = ws.max_row
        cols = ws.max_column
        for r in range(1,rows+1):
            for c in range(1,cols):
                if ws.cell(r,c).value!=None and r!=1 :
                 if 'item.jd.com' in str(ws.cell(r,c+1).value) and str(ws.cell(r,c+1).value).find('i-item.jd.com')==-1:
                     print('支援:'+str(ws.cell(r,c).value)+'|'+str(ws.cell(r,c+1).value))
                     EgongYePing().Init(str(ws.cell(r,c+1).value),str(ws.cell(r,c).value))
                 else:
                     print('當前格式不支援:'+(str(ws.cell(r,c).value)+'|'+str(ws.cell(r,c+1).value)))
                     pass
        pass

if __name__ == "__main__":
                 start = EgongYePing()
                 start.readxlsx(r'C:\Users\newYear\Desktop\爬圖.xlsx')

基本上除了過期的商品無法訪問以外。對於京東的三種頁面結構都做了處理。能訪問到的商品頁面。還做了模擬瀏覽器請求訪問和下載。基本不會被反爬蟲屏蔽下載。

 

 

 上面這一段是以火狐模擬器運行

 

 

 上面這一段是模擬瀏覽器下載。如果不加上這一段。經常會下載幾十張圖片後,很長一段時間無法正常下載圖片。因為沒有請求頭被認為是爬蟲。

 

上面這段是京東的商品詳情頁面,經常會三種?(可能以後會更多的頁面結構)

所以做了三段解析。只要沒有抓到圖片就換一種解析方式。這楊就全了。

 

 京東的圖片基本只存/1.jpg。然後域名是 //img14.360buyimg.com/n0/。所以目前要拼一下。

 

 

 京東還有個很蛋疼的地方是圖片以data-id拼進div的背景元素里。所以取出來的時候要繞一下。還好也解決了。

 

以下是爬取京東商品詳情的Python3程式碼,以excel存放鏈接的方式批量爬取。excel如下

 

因為這次是淘寶和京東一起爬取。所以在一個excel里。程式碼里區分淘寶和京東的鏈接。以下是程式碼

from selenium import webdriver
from lxml import etree
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import datetime
import calendar
import logging
from logging import handlers
import requests
import os
import time
import pymssql
import openpyxl
import xlrd
import codecs



class EgongYePing:

     options = webdriver.FirefoxOptions()
     fp = webdriver.FirefoxProfile()
     fp.set_preference("browser.download.folderList",2)  
     fp.set_preference("browser.download.manager.showWhenStarting",False)
     fp.set_preference("browser.helperApps.neverAsk.saveToDisk","application/zip,application/octet-stream")
     global driver 
     driver= webdriver.Firefox(firefox_profile=fp,options=options)
     def Init(self,url,code):
                       #driver = webdriver.Chrome('D:\python3\Scripts\chromedriver.exe')
                       #driver.get(url)
                       print(url.strip())
                       driver.get(url.strip())
                       #driver.refresh()
                       # 操作瀏覽器屬於非同步,在網路出現問題的時候。可能程式碼先執行。但是請求頁面沒有應答。所以硬等
                       time.sleep(int(3))
                       html = etree.HTML(driver.page_source) 
                       if driver.title!=None:
                         listImg=html.xpath('//*[contains(@id,"J_UlThumb")]//img')
                         if len(listImg)==0:
                              pass
                         if len(listImg)>0:
                                            imgSrc=''
                                            for item in range(len(listImg)):    
                                                 search=listImg[item].attrib
                                                 if 'data-src' in search:
                                                    imgSrc=listImg[item].attrib["data-src"].replace('.jpg_50x50','')
                                                 else:
                                                    imgSrc=listImg[item].attrib["src"]
                                                 if 'http' in imgSrc:
                                                     pass
                                                 else:
                                                     imgSrc='https:'+imgSrc
                                                 print('頭圖下載:'+imgSrc)
                                                 try:
                                                  Headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0'}
                                                  r = requests.get(imgSrc, headers=Headers, stream=True)
                                                  if r.status_code == 200:
                                                     imgUrl=''
                                                     if item==0:
                                                          imgUrl+=code + "_主圖_" + str(item)  + '.' + imgSrc.split('//')[1].split('/')[len(imgSrc.split('//')[1].split('/'))-1].split('.')[1]
                                                     else:
                                                          imgUrl+=code + "_附圖_" + str(item)  + '.' + imgSrc.split('//')[1].split('/')[len(imgSrc.split('//')[1].split('/'))-1].split('.')[1]
                                                     open(os.getcwd()+'/img/'+  imgUrl , 'wb').write(r.content) # 將內容寫入圖片
                                                  del r
                                                 except Exception as e:
                                                    print("圖片禁止訪問:"+imgSrc) 
                         listImg=html.xpath('//*[contains(@id,"J_DivItemDesc")]//img')
                         if len(listImg)>0:
                               for index in range(len(listImg)):  
                                    detailsHTML=listImg[index].attrib
                                    if 'data-ks-lazyload' in detailsHTML:
                                        details= listImg[index].attrib["data-ks-lazyload"]
                                        print("詳情圖下載:"+details)
                                    else:
                                        details= listImg[index].attrib["src"]
                                        print("詳情圖下載:"+details)
                                    try:
                                                  Headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0'}
                                                  r = requests.get(details, headers=Headers, stream=True)
                                                  if r.status_code == 200:
                                                     imgUrl=''
                                                     details=details.split('?')[0]
                                                     imgUrl+=code + "_詳情圖_" + str(index)  + '.' + details.split('//')[1].split('/')[len(details.split('//')[1].split('/'))-1].split('.')[1]
                                                     open(os.getcwd()+'/img/'+   imgUrl, 'wb').write(r.content) # 將內容寫入圖片
                                                  del r
                                    except Exception as e:
                                                    print("圖片禁止訪問:"+details)  
                       print('結束執行')

         

     @staticmethod
     def readxlsx(inputText):
        filename=inputText
        inwb = openpyxl.load_workbook(filename)  # 讀文件
        sheetnames = inwb.get_sheet_names()  # 獲取讀文件中所有的sheet,通過名字的方式
        ws = inwb.get_sheet_by_name(sheetnames[0])  # 獲取第一個sheet內容
        # 獲取sheet的最大行數和列數
        rows = ws.max_row
        cols = ws.max_column
        for r in range(1,rows+1):
            for c in range(1,cols):
                if ws.cell(r,c).value!=None and r!=1 :
                 if 'item.taobao.com' in str(ws.cell(r,c+1).value):
                     print('支援:'+str(ws.cell(r,c).value)+'|'+str(ws.cell(r,c+1).value))
                     EgongYePing().Init(str(ws.cell(r,c+1).value),str(ws.cell(r,c).value))
                 else:
                     print('當前格式不支援:'+(str(ws.cell(r,c).value)+'|'+str(ws.cell(r,c+1).value)))
                     pass
        pass

if __name__ == "__main__":
                 start = EgongYePing()
                 start.readxlsx(r'C:\Users\newYear\Desktop\爬圖.xlsx')

 

淘寶有兩個問題,一個是需要綁定帳號登錄訪問。這裡是程式碼斷點。然後手動走過授權。

 

 

 

 

 第二個是被休息和懶惰載入。被休息。其實沒影響的。一個頁面結構已經載入出來了。然後也不會影響訪問其他的頁面。

 

 

 至於懶惰載入嘛。對我們也沒啥影響。如果不是直接寫在src里那就在判斷一次取 data-ks-lazyload就出來了。

 

 最後就是爬取的片段截圖

 

 建議還是直接將爬取的數據存伺服器,資料庫,或者圖片伺服器。因為程式挺靠譜的。一萬條數據。爬了26個G的文件。最後上傳的時候差點累死了

 

 是真的大。最後還要拆包。十幾個2g壓縮包一個一個上傳。才成功。