Journey

The journey is the destination.

0%

露天拍賣 網路爬蟲

最近想要購買新的筆記型電腦,但是筆記型電腦的品牌/規格又多又複雜,在網站上總是看的頭昏眼花,不如就來寫個爬蟲程式自動幫我們整理出結構化的資料吧!

註:本篇文章僅供研究使用,請勿惡意大量爬取資料造成對方公司的負擔

露天拍賣 爬蟲要點

  1. 在收集產品清單時需要透過 F12 的檢查功能來找出 API
  2. 產品描述要呼叫另外一個 API 來取資料

露天拍賣 爬蟲流程

載入使用套件

1
2
3
4
5
import re
import json
import requests
import pandas as pd
from bs4 import BeautifulSoup

設定 request 參數

在這裡沒有設定 User-Agent 會被拒絕連線,因此當我們無法成功取回資料時的第一個步驟一定是加上 User-Agent 來進行測試!

1
headers = {'User-Agent':'GoogleBot'}

收集產品連結清單

這裡在收集產品清單時使用的 API 要用 F12 的檢查功能來尋找,而在這個 API 中有個 offset 的參數,這是在記錄要從哪裡開始加載更多資料。由於每次查詢是80筆(limit參數),因此每次查詢的 offset 是用 1 + 80*第幾次查詢來抓資料

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 商品分類
cateid = '001100020027'
pages = 50

prodids = []

for page in list(range(1, pages)):
offset = 1 + 80*page
url = 'https://rtapi.ruten.com.tw/api/search/v3/index.php/core/prod?cateid={}&sort=rnk%2Fdc&offset={}&limit=80&2653512&_callback=jsonpcb_CoreProd'.format(cateid, offset)
resp = requests.get(url, headers=headers)
data = re.sub(r'try\{jsonpcb_CoreProd\(|\);\}catch\(e\)\{if\(window.console\)\{console.log\(e\);\}\}','', resp.text)
for prod in json.loads(data)['Rows']:
prodids.append(prod['Id'])
prodids = list(set(prodids))
print('There are {} prods in list.'.format(len(prodids)))

爬取產品資料

  • 這裡在抓產品名稱、幣別、價格、商品分類等等資訊的方法相當單純,就是簡單 request 產品的網址就可以了! 而產品的網址就是在前面「收集產品清單」階段中收集到的產品 ID前面加上’https://goods.ruten.com.tw/item/show?'的網址即可。

    例如ID:30201451592585 產品的網址就是 https://goods.ruten.com.tw/item/show?30201451592585

  • 比較複雜的地方在於產品描述不容易獲取,在這裡有兩個反爬蟲的機制:
    1. request 的網址藏在前面回傳的 descriptionUrl 中

      這裡要花時間找一下產品描述的 API 網址,結果是藏在前面 request 的結果當中。

    2. Referer:要在 request 的 headers 加上 referer,這個參數是告訴對方的伺服器說我們是從哪裡進來到這個API的。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      df = []
      for i, prodid in enumerate(prodids):
      print('='*60)
      print('Dealing with {}: {}'.format(i, prodid))
      headers = {'User-Agent':'GoogleBot'}
      url = 'https://goods.ruten.com.tw/item/show?' + prodid
      resp = requests.get(url, headers=headers)
      soup = BeautifulSoup(resp.text)
      data1 = json.loads(soup.findAll('script',{'type':'application/ld+json'})[0].text)
      data2 = json.loads(soup.findAll('script',{'type':'application/ld+json'})[1].text)
      data3 = json.loads(soup.findAll('script',{'type':'application/ld+json'})[2].text)
      # 產品名稱
      print(data1['name'])
      # 幣別
      print(data1['offers']['priceCurrency'])
      # 價格
      print(data1['offers']['price'])
      # 商品分類
      print(r'/'.join([i['item']['name'] for i in data3['itemListElement']]))
      # 商品描述
      descurl = re.findall(r'goods_comments.php\?id=.*?o=[0-9]{1,}',resp.text)[0]
      descurl = re.sub('&','&',descurl)
      descurl = 'https://goods.ruten.com.tw/item/' + descurl
      headers = {'User-Agent':'GoogleBot',
      'Referer': 'https://goods.ruten.com.tw/item/show?{}'.format(prodid)}
      resp2 = requests.get(descurl, headers=headers)
      soup2 = BeautifulSoup(resp2.text)
      desc = ' '.join(i.text for i in soup2.findAll('p'))

      ndf = pd.DataFrame([{'name': data1['name'],
      'description':data1['description'],
      'productId':data1['productId'],
      'brand_name':data1['brand']['name'],
      'priceCurrency':data1['offers']['priceCurrency'],
      'price':data1['offers']['price'],
      'contentLocation':data2['contentLocation'],
      'item_name':r'/'.join([i['item']['name'] for i in data3['itemListElement']]),
      'describe':desc}])
      df.append(ndf)

      df = pd.concat(df, ignore_index=True)

爬取結果

最後總共抓取了 3,920 個產品的資訊,包含了產品ID、名稱、價格、賣家名稱、商品位置、商品描述等等資訊,詳細資訊如下

1
df.info()

保存資料

抓完資料記得保存結果,不然你會需要重新再抓一次>”<

1
df.to_excel('./RuTen.xlsx')

附件