Python神器!爬取京東手機上萬的商品數據


Python神器!爬取京東手機上萬的商品數據


Charles是一個網絡抓包工具,我們可以用它來做App的抓包分析,得到App運行過程中發生的所有網絡請求和響應內容,這就和Web端瀏覽器的開發者工具Network部分看到的結果一致。

相比Fiddler來說,Charles的功能更強大,而且跨平臺支持更好。所以我們選用Charles作爲主要的移動端抓包工具,用於分析移動App的數據包,輔助完成App數據抓取工作。

一、本節目標

本節我們以京東App爲例,通過Charles抓取App運行過程中的網絡數據包,然後查看具體的Request和Response內容,以此來了解Charles的用法。

二、準備工作

請確保已經正確安裝Charles並開啓了代理服務,手機和Charles處於同一個局域網下,Charles代理和CharlesCA證書設置好。

三、原理

首先Charles運行在自己的PC上,Charles運行的時候會在PC的8888端口開啓一個代理服務,這個服務實際上是一個HTTP/HTTPS的代理。

確保手機和PC在同一個局域網內,我們可以使用手機模擬器通過虛擬網絡連接,也可以使用手機真機和PC通過無線網絡連接。

設置手機代理爲Charles的代理地址,這樣手機訪問互聯網的數據包就會流經Charles,Charles再轉發這些數據包到真實的服務器,服務器返回的數據包再由Charles轉發回手機,Charles就起到中間人的作用,所有流量包都可以捕捉到,因此所有HTTP請求和響應都可以捕獲到。同時Charles還有權力對請求和響應進行修改。

四、抓包

初始狀態下Charles的運行界面如下圖所示。

Python神器!爬取京東手機上萬的商品數據


Charles會一直監聽PC和手機發生的網絡數據包,捕獲到的數據包就會顯示在左側,隨着時間的推移,捕獲的數據包越來越多,左側列表的內容也會越來越多。

可以看到,圖中左側顯示了Charles抓取到的請求站點,我們點擊任意一個條目便可以查看對應請求的詳細信息,其中包括Request、Response等內容。

接下來清空Charles的抓取結果,點擊左側的掃帚按鈕即可清空當前捕獲到的所有請求。然後點擊第二個監聽按鈕,確保監聽按鈕是打開的,這表示Charles正在監聽App的網絡數據流,如下圖所示。

Python神器!爬取京東手機上萬的商品數據


這時打開手機京東,注意一定要提前設置好Charles的代理並配置好CA證書,否則沒有效果。

打開任意一個商品,如iPhone,然後打開它的商品評論頁面,如下圖示。

Python神器!爬取京東手機上萬的商品數據


不斷上拉加載評論,可以看到Charles捕獲到這個過程中京東App內發生的所有網絡請求,如下圖所示。

Python神器!爬取京東手機上萬的商品數據


左側列表中會出現一個api.m.jd.com鏈接,而且它在不停閃動,很可能就是當前App發出的獲取評論數據的請求被Charles捕獲到了。我們點擊將其展開,繼續上拉刷新評論。隨着上拉的進行,此處又會出現一個個網絡請求記錄,這時新出現的數據包請求確定就是獲取評論的請求。

爲了驗證其正確性,我們點擊查看其中一個條目的詳情信息。切換到Contents選項卡,這時我們發現一些JSON數據,覈對一下結果,結果有commentData字段,其內容和我們在App中看到的評論內容一致,如下圖所示。

Python神器!爬取京東手機上萬的商品數據


這時可以確定,此請求對應的接口就是獲取商品評論的接口。這樣我們就成功捕獲到了在上拉刷新的過程中發生的請求和響應內容。

五、分析

現在分析一下這個請求和響應的詳細信息。首先可以回到Overview選項卡,上方顯示了請求的接口URL,接着是響應狀態Status Code、請求方式Method等,如下圖所示。

Python神器!爬取京東手機上萬的商品數據


這個結果和原本在Web端用瀏覽器開發者工具內捕獲到的結果形式是類似的。

接下來點擊Contents選項卡,查看該請求和響應的詳情信息。

上半部分顯示的是Request的信息,下半部分顯示的是Response的信息。比如針對Reqeust,我們切換到Headers選項卡即可看到該Request的Headers信息,針對Response,我們切換到JSON TEXT選項卡即可看到該Response的Body信息,並且該內容已經被格式化,如下圖所示。

Python神器!爬取京東手機上萬的商品數據


由於這個請求是POST請求,我們還需要關心POST的表單信息,切換到Form選項卡即可查看,如下圖所示。

Python神器!爬取京東手機上萬的商品數據


這樣我們就成功抓取App中的評論接口的請求和響應,並且可以查看Response返回的JSON數據。

至於其他App,我們同樣可以使用這樣的方式來分析。如果我們可以直接分析得到請求的URL和參數的規律,直接用程序模擬即可批量抓取。

六、重發

Charles還有一個強大功能,它可以將捕獲到的請求加以修改併發送修改後的請求。點擊上方的修改按鈕,左側列表就多了一個以編輯圖標爲開頭的鏈接,這就代表此鏈接對應的請求正在被我們修改,如下圖所示。

Python神器!爬取京東手機上萬的商品數據


我們可以將Form中的某個字段移除,比如這裏將partner字段移除,然後點擊Remove。這時我們已經對原來請求攜帶的Form Data做了修改,然後點擊下方的Execute按鈕即可執行修改後的請求,如下圖所示。

Python神器!爬取京東手機上萬的商品數據


可以發現左側列表再次出現了接口的請求結果,內容仍然不變,如下圖所示。

Python神器!爬取京東手機上萬的商品數據


刪除Form表單中的partner字段並沒有帶來什麼影響,所以這個字段是無關緊要的。

有了這個功能,我們就可以方便地使用Charles來做調試,可以通過修改參數、接口等來測試不同請求的響應狀態,就可以知道哪些參數是必要的哪些是不必要的,以及參數分別有什麼規律,最後得到一個最簡單的接口和參數形式以供程序模擬調用使用。

七、結語

以上內容便是通過Charles抓包分析App請求的過程。通過Charles,我們成功抓取App中流經的網絡數據包,捕獲原始的數據,還可以修改原始請求和重新發起修改後的請求進行接口測試。

知道了請求和響應的具體信息,如果我們可以分析得到請求的URL和參數的規律,直接用程序模擬即可批量抓取!

文末知識點摘要:Python解惑之:整數比較

在 Python 中一切都是對象,毫無例外整數也是對象,對象之間比較是否相等可以用 ==,也可以用 is。 ==和 is操作的區別是:

  • is比較的是兩個對象的id值是否相等,也就是比較倆對象是否爲同一個實例對象,是否指向同一個內存地址。

  • ==比較的是兩個對象的內容是否相等,默認會調用對象的 __eq__()方法。

清楚 is和 ==的區別之後,對此也許你有可能會遇到下面的這些困惑,於是就有了這樣一篇文章,試圖把Python中一些隱晦的東西趴出來,希望對你有一定的幫助。我們先來看兩段代碼:

片段一:

  1. >>> a = 256

  2. >>> b = 256

  3. >>> a == b

  4. True

  5. >>>

片段二:

  1. >>> a = 256

  2. >>> b = 256

  3. >>> a is b

  4. True

  5. >>>

在交互式命令行執行上面兩段代碼,代碼片段一中的 a==b返回 True很好理解,因爲兩個對象的值都是256,對於片段二, a is b也返回True,這說明a和b是指向同一個對象的,可以檢查一下他們的id值是否相等:

  1. >>> id(a)

  2. 8213296

  3. >>> id(b)

  4. 8213296

  5. >>>

結果證明他倆的確是同一個對象,指向的是同一個內存地址。那是不是所有的整數對象只要兩個對象的值(內容)相等,它們就是同一個實例對象呢?換句話說,對於整數對象只要 ==返回 True, is操作也會返回 True嗎?帶着這個問題來看下面這兩段代碼:

片段一:

  1. >>> a = 257

  2. >>> b = 257

  3. >>> a == b

  4. True

  5. >>>

片段二:

  1. >>> a = 257

  2. >>> b = 257

  3. >>> a is b

  4. False

  5. >>>

對於257, a is b返回的竟然是False,結果可能在你的意料之中,也有可能出乎你的意料,但不管怎麼,我們還是要刨根問底,找出問題的真相。

解惑一

出於對性能的考慮,Python內部做了很多的優化工作,對於整數對象,Python把一些頻繁使用的整數對象緩存起來,保存到一個叫 small_ints的鏈表中,在Python的整個生命週期內,任何需要引用這些整數對象的地方,都不再重新創建新的對象,而是直接引用緩存中的對象。Python把這些可能頻繁使用的整數對象規定在範圍[-5, 256]之間的小對象放在 small_ints中,但凡是需要用些小整數時,就從這裏面取,不再去臨時創建新的對象。因爲257不再小整數範圍內,因此儘管a和b的值是一樣,但是他們在Python內部卻是以兩個獨立的對象存在的,各自爲政,互不干涉。


弄明白第一個問題後,我們繼續在Python交互式命令行中寫一個函數,再來看下面這段代碼:

片段一:

  1. >>> c = 257

  2. >>> def foo():

  3. ... a = 257

  4. ... b = 257

  5. ... print a is b

  6. ... print a is c

  7. ...

  8. >>> foo()

  9. True

  10. False

呃,什麼情況,是的,你沒看錯,片段一中的這段代碼 a、b 值都是257的情況下,出現了 a is b返回 True,而 a is c 返回的 False,a、b、c的值都爲257,爲什麼會出現不同的結果呢?這對於剛剛好不容易建立起來的認知就被徹底否決了嗎,那這段代碼中究竟發生了什麼?難道解惑一中的結論是錯誤的嗎?

解惑二

A Python program is constructed from code blocks. A block is a piece of Python program text that is executed as a unit. The following are blocks: a module, a function body, and a class definition. Each command typed interactively is a block. A script file (a file given as standard input to the interpreter or specified as a command line argument to the interpreter) is a code block. A script command (a command specified on the interpreter command line with the ‘-c‘ option) is a code block. structure-of-a-program

爲了弄清楚這個問題,我們有必要先理解程序代碼塊的概念。Python程序由代碼塊構成,代碼塊作爲程序的一個最小基本單位來執行。一個模塊文件、一個函數體、一個類、交互式命令中的單行代碼都叫做一個代碼塊。在上面這段代碼中,由兩個代碼塊構成, c = 257作爲一個代碼塊,函數 foo作爲另外一個代碼塊。Python內部爲了將性能進一步的提高,凡是在一個代碼塊中創建的整數對象,如果存在一個值與其相同的對象於該代碼塊中了,那麼就直接引用,否則創建一個新的對象出來。Python出於對性能的考慮,但凡是不可變對象,在同一個代碼塊中的對象,只有是值相同的對象,就不會重複創建,而是直接引用已經存在的對象。因此,不僅是整數對象,還有字符串對象也遵循同樣的原則。所以 a is b就理所當然的返回 True了,而 c和 a不在同一個代碼塊中,因此在Python內部創建了兩個值都是257的對象。爲了驗證剛剛的結論,我們可以借用 dis模塊從字節碼的角度來看看這段代碼。

Python神器!爬取京東手機上萬的商品數據


可以看出兩個257都是從常量池的同一個位置 co_consts[1]獲取的。

總結

一番長篇大論之後,得出兩點結論:1、小整數對象[-5,256]是全局解釋器範圍內被重複使用,永遠不會被GC回收。2、同一個代碼塊中的不可變對象,只要值是相等的就不會重複創建新的對象。似乎這些知識點對日常的工作一點忙也幫不上,因爲你根本不會用 is來比較兩個整數對象的值是否相等。那爲什麼還要拿出來討論呢?嗯,程序員學知識,不應該淺嘗輒止,要充分發揮死磕到底的精神。

手機爬蟲非常有意思,而且可以爬取的數據非常多,當然還有很多東西要學。以後我也會寫一些實戰的有趣案例給大家。

如果你也是想要學習Python爬蟲的話,不妨點擊文章底部左側的瞭解更多看看,爲你分享的一個三大案列入門Python爬蟲的課程。

本篇文章的分享到此結束,文章來源網絡,如有侵權,請聯繫刪除。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章