利用Python抓取亞馬遜評論列表數據


  前段時間,我家妹子公司老板叫她去將法國亞馬遜評論列表的前100頁共1000個評論用戶的聯系方式找出來。1000個用戶,要一個個的去看再記錄下來,而且並不是每個評論用戶都會將個人的聯系方式留下來。那么問題來了,這樣費時費力的工作如果人工去做的話,那么就是花了兩天的時間也就找了前30頁的數據(還有別的工作要做),然后累的夠嗆的。本着心疼的原則(程序猿能找到妹子就很不錯了,所以得心疼着),就想幫着她做點事。

  我本身的工作是做游戲客戶端開發的,主要使用的開發語言是lua和c++,並沒有接觸過網頁、網站相關的工作。只是工作中有用到過python腳本,然后有一次在網上查python的相關資料的時候,有看到網友用python寫爬蟲干點事的。所以我就想,我是否也能夠實用python來寫爬蟲去亞馬遜的網站抓取數據呢?就這樣現學現用的開始敲起代碼來了。


環境:

  windows7

  python:2.7

利用的python插件:

  urllib2、urllib插件,用了打開網頁鏈接;

  re插件,用來做正則匹配;

  codecs插件,用來做編碼轉換及數據保存。

目前實現的功能:

  抓取法國亞馬遜top-viewer列表前100頁共1000個用戶的姓名、聯系方式(網站鏈接或者郵箱)、國籍(可能有盧森堡、瑞士的買家在法國亞馬遜購買)、用戶評論詳細頁面的鏈接等數據。

  通過抓取法國亞馬遜top-viewer列表數據,進而擴展到抓取中國亞馬遜、美國亞馬遜top-viewer列表的數據。理論上通過簡單的修改可以抓取不同國家亞馬遜top-viewer列表的數據。

需改進的地方:

  代碼寫好之后,抓取數據的過程中發現效率好低,1000個數據需要花費很長的時間才能抓取完,而且抓取了幾頁或者幾十頁之后程序就跑不動了,卡住只能關掉再開。當時在沒有擴展到抓取中國、美國亞馬遜的數據之前,我想到的可能原因有:

  1. 正則表達式有優化空間,因為我之前沒有接觸過正則表達式,沒有使用過;
  2. 法國亞馬遜網站在國內訪問速度慢,影響到了數據的抓取;
  3. python沒有系統的學過,在一些語法或者第三方輔助插件的使用上不夠熟悉。

  以上三點是我想到的造成抓取效率低下的可能的原因。后來我把同一套代碼擴展到抓取中國、美國亞馬遜的數據,以驗證第二條原因對整個抓取工作的影響程度,結果發現影響非常大!同樣的帶寬、硬件條件下,中國、美國的前100頁共1000個評論用戶,抓取大概花了半個多小時,而抓取法國的那1000個數據,花了我近一個下午的時間(因為總是卡住不動,我想應該是urllib打開網頁未響應而我的程序沒有做判斷)才陸陸續續的抓取完,不過也總比妹子一個一個的打開網頁再記錄下來好,至少人不會煩!然后對中國、美國數據抓取花了半個小時時間,對這個時間花費我個人不好評判是花多了還是說差不多了。但是作為一個開發人員來說,程序總是可以做優化的!

思路:

  當時看到網友寫的爬蟲,思路就是打開網頁、匹配自己需要的信息。因此我的思路也是跟着這個來的:通過python的urllib和urllib2插件打開頁面,再轉換為html數據,利用python的re正則插件去做正則匹配,得到頁面、用戶詳細信息頁面、用戶聯系方式等信息。

具體實現:

1、法國亞馬遜的top評論列表大概有1000個網頁,每個頁面有10個用戶數據。每個頁面,除了第一頁的鏈接外,其它頁面的鏈接都跟頁面數相關,如http://xxx.page23.xxx 是代表23頁的數據,因此可以通過簡單的字符串拼接就可以得到1000個頁面的頁面鏈接了。這是關於得到各個頁面鏈接的方法;示例代碼如下:
a、拼接頁面鏈接,因為第一頁和其余頁的格式稍微有點不同,所以分開來處理:
if 1 == i:
    html_link = "http://www.amazon.fr/review/top-reviewers/ref=cm_cr_tr_link_" + str(i);
else:
    html_link = "http://www.amazon.fr/review/top-reviewers/ref=cm_cr_tr_link_" + str(i) + "?ie=UTF8&page=" + str(i);

b、將頁面轉為html:

try:
    page = urllib.urlopen(url)
    html = page.read()
    return html
except:
    print "getHtml2 error"

我使用了try、except就是想看能不能處理打開不開網頁的問題(我猜法國亞馬遜抓取卡死是因為網站未響應了),但是沒有效果;

2、每個頁面有10個用戶的數據,點開一個用戶會跳轉到其詳細信息頁面,通過查看不同詳細信息頁面的鏈接形式,發現都是類似的:一個可能是用戶名的變量,一個表示該用戶在評論列表中的排名值。因此我可以想辦法得到用戶名(猜想是用戶名、或者是亞馬遜保存的一個唯一標示)、用戶在評論列表中的排名,然后拼接出用戶詳細信息頁面的鏈接;通過查看頁面的源碼,發現每個頁面中,用戶信息的形式類似,都是諸如:/gp/pdp/profile/xxxx/這樣的形式,因此可以通過簡單的正則匹配得到xxxx這個數據,暫且稱為用戶唯一標示符。這是關於得到詳細頁面鏈接的方法;示例代碼:
a、匹配每個用戶的唯一標示符:
reg = r'href="(/gp/pdp/profile/.+?)"><b>'
captureRe = re.compile(reg)
cpList = re.findall(captureRe,html)

b、拼湊鏈接:

num = (i - 1) * 10 + index;
subLink = "http://www.amazon.fr" + cp + "/ref=cm_cr_tr_tbl_" + str(num) + "_name";

index指的是10個數據中具體哪個,num其實就是用戶在評論列表中的排名,一頁10個,所以能根據頁碼及index來算出具體的排名;

c、轉為html:

headers = { #偽裝為瀏覽器抓取
    'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'
    }
req = urllib2.Request(url,headers=headers)
page = "";
try:
    page = urllib2.urlopen(req)
    html = page.read()
    return html
except:
    print "getHtml error"

可以看到這個跟前面的那個轉換形式不一樣,因為我發現利用前一種轉換方式得到的頁面數據,跟我們之間右鍵瀏覽器查看源代碼的格式是有差異的,然后我在匹配聯系方式的時候一直匹配失敗,就以為是這個差異造成的。因此就查找了資料使用了上述形式來轉換,網友也說這樣能防止亞馬遜針對頻繁訪問的ip做封ip處理;

3、不是每個評論者都提供了聯系方式,但是提供了聯系方式的只有兩種形式:一個網站鏈接(博客或者啥);一個郵箱。通過查看源碼發現:提供網站鏈接的,在源碼中會有一個nofollow標簽,而提供郵箱的則有一個mailto:關鍵詞。有了這兩個信息,那么我就可以據此來做正則匹配了。這就是關於得到聯系方式的方法。這里也是兩個正則表達式做正則匹配,跟上述代碼類似就不上代碼了;
 
4、后面又通過正則匹配得到了評論人姓名、國籍等信息。操作也跟3中提到的類似。
缺陷:
  1. 正如我在問題中提到的,抓取效率是一個大問題。1000個數據快都需要花費半個小時才能匹配抓取完,自我感覺效率上還可以提升;
  2. 在抓取法國亞馬遜top-viewer數據的時候,程序一直卡死,但是我不能據此做問題處理,需再查查。

寫在最后:
  這個小腳本大概花了一個下午的時間才折騰出來,然后又花了些時間去滿足妹子提的其他需求,第二天才把最終抓取到的數據發送給妹子使用。但總的來說,比起妹子可能要花1個禮拜才能做完,我也是幫了點小忙了。而我自己本身也學到了東西: 數據抓取!雖然我這只是簡單得不能再簡單的一種實現,但是也相當於稍微入了門,積累了點知識!


免責聲明!

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



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