爬取淘寶高清圖片


老婆總是為每天搭配什么衣服煩惱,每天早上對穿什么衣服是各種糾結,我就在想,何不看一下淘寶上的模特都是怎么穿的呢,正好在學python scrapy 爬蟲。何不把淘寶上的高清圖爬下來呢。
環境配置:python3+scrapy

一 寫 spider下tb.py

  1,寫start_requests函數
1     def start_requests(self):
2         return [scrapy.Request(url="https://www.taobao.com/",  callback=self
 
        
    def start_requests(self):
        return [scrapy.Request(url="https://www.taobao.com/",  callback=self.start_search)]
從淘寶首頁開始,這里我沒有寫headers是因為我會在middlewares中寫隨機更換UA和IP的middlewares.py,回調函數是start_search,這一步比較簡單

  2、下一步:start_search函數,這一步會讓我選擇爬取的關鍵字,然后進入淘寶的搜索列表頁面,
    def start_search(self,response):
        keyword = input("please input what do you what to seach ?").strip()
        keyword = urllib.request.quote(keyword)
        for i in range(1,2): # 這里可以優化,可以寫一個自動判斷是否還有下一頁的函數
            url = "https://s.taobao.com/search?q=" + keyword + "&s=" + str(i * 44)
            yield scrapy.Request(url=url,callback=self.parse_search_page)
            time.sleep(20)
 
        

這一步就遇到困難了,因難一,淘寶會不定時跳轉到登錄頁面。我嘗試了很多方法都沒有完成淘寶的登錄,這個后續要繼續學習,困難二,淘寶的網頁大部分是非常動太加載,得到的response 中根本根本不能用xpath和css做選擇,不過可以用到正則,

下面是淘寶部分網頁

 
        
<link rel="dns-prefetch" href="//res.mmstat.com" />
<link href="//img.alicdn.com/tps/i3/T1OjaVFl4dXXa.JOZB-114-114.png" rel="apple-touch-icon-precomposed" />
<style>
  blockquote,body,button,dd,dl,dt,fieldset,form,h1,h2,h3,h4,h5,h6,hr,input,legend,li,ol,p,pre,td,textarea,th,ul{margin:0;padding:0}body,button,
 
        

全是動態加載,不過這樣也好,直接用正剛提取,我發現詳情頁面是用uid 來標示的,所以我直接以正則表達式提取Uid

淘寶原頁面代碼如下:

 

  從上圖可以看出taobao把這一頁的商品的Nid都放在一個列表中,這就好辦了啊,用uids = re.compile('auctionNids\"\:\[\"(.*?)\"\]').findall(html)[0].split(",")這個正則把所有的列表取出來,然后拼接商品詳情頁面

for uid in uids 
  detailUrl = "https://detail.tmall.com/item.htm?id=" + uid

  在這里就出錯了,部是返回500的錯誤,排查了好久,終於發現,淘寶詳情頁面分兩種,一種是淘寶,一種是天貓,他倆的詳情頁面是不相同的,這就必須要到源碼去找了

下面是部分源碼:

從源碼去可以看到,這里面  isTmall  就是指是淘寶還是天貓,當然可以用正則表達式把這個字段提取出來,但是這個提取出來后,怎么會和前面提取的Nid 一一對應呢,不一一對應也是會出錯的,而且源碼中沒有isTmall 這樣一個列表,所以只能重新把新的方法,不能由上方的那個列表來獲取Nid,通過幾次的試驗,下面這個正剛可以取出來,

uids_and_isTmail = re.compile(r'"nid":"(.*?)".*?"isTmall":(.*?),').findall(html)

這個正則可以取出nid號,還可以取出isTmall的值,這樣就可以把詳情頁面的url拼接起來

uids_and_isTmail = re.compile(r'"nid":"(.*?)".*?"isTmall":(.*?),').findall(html)
            for uid_and_isTmail in uids_and_isTmail:
                if uid_and_isTmail[1] == "true":
                    detailUrl = "https://detail.tmall.com/item.htm?id=" + str(uid_and_isTmail[0])
                else:
                    detailUrl = "https://item.taobao.com/item.htm?id=" + str(uid_and_isTmail[0])

  這樣把詳情頁面的代碼拼接好后,加上異常處理,就可以讓下一個函數來處理這些詳情頁面

    parse_search_page函數代碼如下:

    def parse_search_page(self, response):
        """處理搜索頁面"""
        html = response.body.decode("utf8", "ignore")
        try:
            # 查找uid 和是否屬於天貓,因為淘寶和天貓的詳情頁面不一樣,得到是一個tupe
            uids_and_isTmail = re.compile(r'"nid":"(.*?)".*?"isTmall":(.*?),').findall(html)
            for uid_and_isTmail in uids_and_isTmail:
                if uid_and_isTmail[1] == "true":
                    detailUrl = "https://detail.tmall.com/item.htm?id=" + str(uid_and_isTmail[0])
                else:
                    detailUrl = "https://item.taobao.com/item.htm?id=" + str(uid_and_isTmail[0])
                yield scrapy.Request(detailUrl, callback=self.parsePictureUrl)
                time.sleep(10)#友好的爬蟲
        except Exception as e:
            print(e)

接下就要編寫詳情頁面返回的數據的函數:

我想要的是高清大圖,也就是淘寶中商品詳情的圖片,通過查源碼發現,這些圖片也是動態加載的,源碼中根本找不到這些高清大圖的url,經過抓包分析后,發現加載動態高清圖的網頁存在源碼中,

這里descUrl就是高清大圖的url,提取到這一步就簡單了,直接用re 提取就行了,pictureUrl = re.compile('descUrl.*?:.*?//(.*?)\'').findall(html)[0]

  結里這里去訪問時又出錯了,在瀏覽器里打開網頁能打開,scrapy 就是會報500的錯,排查了好久發現,瀏覽器會自動加一個http://,加的這個http://不會在地址欄中顯示,但是實際請求的網頁會加上這個,所以又要拼接Url,代碼如下:

 

    def parsePictureUrl(self, response):
        """通過詳情頁面得到存放高清圖片的網址"""
        html = response.body.decode("utf8", "ignore")
        try:
            pictureUrl = re.compile('descUrl.*?:.*?//(.*?)\'').findall(html)[0]
            #必須加http才能訪問
            pictureUrl = "http://" + pictureUrl
            yield scrapy.Request(pictureUrl, callback=self.parsePicture)
        except Exception as e:
            print(e)

 

這個函數返回一個的數據,里面就有各個高清圖的詳細下載網址,源碼截圖

 

img src 里面就是存放的各個圖片的下載網址,這里可以用xpath 或css進行提取,我這里還是用的正則進行提取:

 

    def parsePicture(self, response):
        """打開存放高清圖片的網址后得到是一個json文件,里面有各個高清圖片的詳細網址,得到這些詳細網址,然后交由scrapy下載"""
        item = TbItem()
        html = response.body.decode("utf8","ignore")
        try:
            downPictureUrlList = re.compile('src=.*?\"(.*?)\"').findall(html)
            for downPictureUrl in downPictureUrlList:
                item["img"] = [downPictureUrl]
                yield item
        except:
            print("can not find down page")

 

 

 

到此spider 的代碼寫完了,淘寶的高清圖片隱藏很深,需要進行三層才能到真正的下載地址,這里面也有很多坑,接下來就是Item.py的代碼

item.py 很簡單,我暫時只保存圖片,就只有一個字段,之后可以添加

 

class TbItem(scrapy.Item):
    img=scrapy.Field()

 

二 、接下來是settings 中代碼

  1,設置自動下載的字段和保存的位置,

import os
img_dir=os.path.join(os.path.abspath(os.path.dirname(__file__)),"images")
print(img_dir)
IMAGES_URLS_FIELD='img'
IMAGES_STORE=img_dir

2,加下自動下載圖片的類

ITEM_PIPELINES = {
   # 'taobao.pipelines.TaobaoPipeline': 300,
    'scrapy.pipelines.images.ImagesPipeline':1
}

3,ROBOTSTXT_OBEY = False

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

 

4,設置隨機更換UA和IP的類

DOWNLOADER_MIDDLEWARES = {
   'taobao.middlewares.RandomIpAndUserAgentMiddleware': 543,
   'taobao.middlewares.TaobaoSpiderMiddleware': None,
}

5,因為是scrapy 自動下載圖片,所以不用自已寫pipelines,但是要加上scrapy 的自動下載類

ITEM_PIPELINES = {
   # 'taobao.pipelines.TaobaoPipeline': 300,
    'scrapy.pipelines.images.ImagesPipeline':1
}

到此settings設置完成,

在middleware中設置隨機更換UA和IP的類會在另外一篇博客中寫到,這里不贅述。

三 、到些整個爬蟲代碼完結,下面把整個spider.py附上,方便查看

 1 # -*- coding: utf-8 -*-
 2 import scrapy
 3 import re
 4 import time
 5 import urllib.request
 6 from taobao.items import TbItem
 7 
 8 
 9 class TbSpider(scrapy.Spider):
10     name = 'tb'
11     allowed_domains = ['tabao.com', "detail.tmall.com", "s.taobao.com", "item.taobao.com", "dsc.taobaocdn.com",
12                        "img.alicdn.com"]
13     start_urls = ['https://www.taobao.com/']
14 
15 
16     def start_requests(self):
17         return [scrapy.Request(url="https://www.taobao.com/",  callback=self.start_search)]
18 
19 
20     def start_search(self,response):
21         keyword = input("please input what do you what to seach ?").strip()
22         keyword = urllib.request.quote(keyword)
23         for i in range(1,2): # 這里可以優化,可以寫一個自動判斷是否還有下一頁的函數
24             url = "https://s.taobao.com/search?q=" + keyword + "&s=" + str(i * 44)
25             yield scrapy.Request(url=url,callback=self.parse_search_page)
26             time.sleep(20)
27 
28     def parse_search_page(self, response):
29         """處理搜索頁面"""
30         html = response.body.decode("utf8", "ignore")
31         try:
32             # 查找uid 和是否屬於天貓,因為淘寶和天貓的詳情頁面不一樣,得到是一個tupe
33             uids_and_isTmail = re.compile(r'"nid":"(.*?)".*?"isTmall":(.*?),').findall(html)
34             for uid_and_isTmail in uids_and_isTmail:
35                 if uid_and_isTmail[1] == "true":
36                     detailUrl = "https://detail.tmall.com/item.htm?id=" + str(uid_and_isTmail[0])
37                 else:
38                     detailUrl = "https://item.taobao.com/item.htm?id=" + str(uid_and_isTmail[0])
39                 yield scrapy.Request(detailUrl, callback=self.parsePictureUrl)
40                 time.sleep(10)
41         except Exception as e:
42             print(e)
43 
44     def parsePictureUrl(self, response):
45         """通過詳情頁面得到存放高清圖片的網址"""
46         html = response.body.decode("utf8", "ignore")
47         try:
48             pictureUrl = re.compile('descUrl.*?:.*?//(.*?)\'').findall(html)[0]
49             #必須加http才能訪問
50             pictureUrl = "http://" + pictureUrl
51             yield scrapy.Request(pictureUrl, callback=self.parsePicture)
52         except Exception as e:
53             print(e)
54 
55     def parsePicture(self, response):
56         """打開存放高清圖片的網址后得到是一個json文件,里面有各個高清圖片的詳細網址,得到這些詳細網址,然后交由scrapy下載"""
57         item = TbItem()
58         html = response.body.decode("utf8","ignore")
59         try:
60             downPictureUrlList = re.compile('src=.*?\"(.*?)\"').findall(html)
61             for downPictureUrl in downPictureUrlList:
62                 item["img"] = [downPictureUrl]
63                 yield item
64         except:
65             print("can not find down page")

四、下面對這次代碼做總結:

學到的知識

一,對整個basic spider的詳細處理流程有了個清楚的認識。明白了scrapy 各函數的數據流程,

二,學會看網頁源代碼,淘寶網頁都是動態加載,要想得到你要的東西得經過好幾層的挖掘,但是總會有規律。

三,學會用異常處理。異常處理太重要了,他讓程序不致於因一個url出錯而停止。

四,scrapy的調試,做爬蟲時,會調試真的很重要。

還需要學習的知識:

一,scrapy 日志系統,怎么記錄scrapy 的日志,

二,學會模擬登錄,我上次模擬登錄知乎都沒有出錯,這次出錯,不知道是什么原因,

三,學會數據庫處理,但學習入mysql 再學習入mongodb

 

程序的不足

一、只是把圖年保存到本地,后期會加入到保存到數據庫的代碼
二、目前只是測試了服裝類,其他類未測試
三、目前只是能保存圖片,如果在瀏覽圖片時看到某個圖片所展示的衣服很好看,不能根據該圖片追蹤到淘寶店鋪,不能篩選同類型的圖片


最后附上github :https://github.com/573320328/taobao

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM