在製作 電商歷史價格查詢 時,發現 momo 手機 app 分享商品網址會是一個短網址,這會導致無法查詢到對應的商品,因此有轉換為一般 momo 網址的需求,這篇文章就這麼誕生了。
推廣一下自己做的 電商歷史價格查詢,最主要是致敬 TWBuyer.info,覺得使用網址來查詢價格非常方便、直覺,但可惜網站不知道什麼原因下架了 🥲
先來稍微講解 momo 短網址的流程
graph LR; A[短網址]-->B[接收_HTTP_301]; B-->C[完整商品網址]
什麼是 HTTP 301? 這邊簡單的介紹:
| Status code | 用途 |
|---|---|
| 301 Moved Permanently | 表示請求的資源已被永久地移動到由 Location 標頭給出的 URL |
| 302 Found | 表示所請求的資源已暫時移動到由 Location 標頭給出的 URL |
| 307 Temporary Redirect | 與 302 回應相同,主要差異是用戶端不會更改重新導向請求的方法與主體。 舉例來說,使用 POST 傳遞資料時,302 會使舊版用戶端將方法改為 GET,而 307 不會。 |
| 308 Permanent Redirect | 與 301 回應相同,主要差異是用戶端不會更改重新導向請求的方法與主體。 |
Steps #
首先,當然要有一台可以運行的主機(這什麼廢話 🫤
- 已安裝 Python3、pip
-
安裝 requests 套件
pip install requests -
複製和稍微了解 Code
載入剛剛安裝的套件和其他程式庫
import requests from urllib.parse import urlparse, parse_qs來到主程式,這邊假設我要找的商品短網址是
https://momo.dm/fiaiym。將短網址傳遞到 Function,最後輸出完整商品網址。
if __name__ == "__main__": short_url = "https://momo.dm/fiaiym" destination_url = resolve_momo_short_url(short_url) parse_url = parse_momo_short_url(destination_url) if destination_url: print(f"The destination URL for {short_url} is: {destination_url}") print(f"Parsed goodsUrl: {parse_url}") else: print(f"Could not resolve {short_url}")當中的 Function
resolve_momo_short_url(short_url)用途是將短網址傳送一個要求,嘗試看看主機回傳什麼資料。這邊有一個需要注意的地方,
allow_redirects要設定為False,否則你就被他導過去拉 🤣。如果有找到轉向的 Location,則回傳 Location URL。
def resolve_momo_short_url(short_url:str): try: response = requests.get(short_url, allow_redirects=False) if response.status_code in [301, 302, 307, 308]: return response.headers['Location'] else: print( f"Unexpected status code: {response.status_code} for {short_url}") return None except requests.exceptions.RequestException as e: print(f"Error resolving {short_url}: {e}") return None若執行正常的話,回傳結果應該會類似這樣的樣式:
{ "statusCode": 301, "location": "https://www.momoshop.com.tw/event/appRedirect.jsp?status=0&goodsUrl=https://m.momoshop.com.tw/goods.momo?i_code=12655371&simOrderYn=0" }可以看到 Requests 回傳確實有出現
location和其他欄位。接著我們要處理這段 Redirected URL。
parse_momo_short_urlFunction 的用途是將導向的 URL 提取出來。從回傳的 URL 可以看到當中其實是帶有許多的參數,而主要對我們有用的參數是goodsUrl,因此透過urllib的urlparse,將網址中的資料進行分段。def parse_momo_short_url(destination_url): # 解析網址 parsed_url = urlparse(destination_url) # 解析 query 部分為字典 query_params = parse_qs(parsed_url.query) goodsUrl = query_params.get('goodsUrl', [""])[0] return goodsUrl整合起來的程式碼:
import requests from urllib.parse import urlparse, parse_qs def resolve_momo_short_url(short_url): try: response = requests.get(short_url, allow_redirects=False) if response.status_code in [301, 302, 307, 308]: return response.headers['Location'] else: print( f"Unexpected status code: {response.status_code} for {short_url}") return None except requests.exceptions.RequestException as e: print(f"Error resolving {short_url}: {e}") return None def parse_momo_short_url(destination_url): # 解析網址 parsed_url = urlparse(destination_url) # 解析 query 部分為字典 query_params = parse_qs(parsed_url.query) goodsUrl = query_params.get('goodsUrl', [""])[0] return goodsUrl if __name__ == "__main__": short_url = "https://momo.dm/fiaiym" destination_url = resolve_momo_short_url(short_url) parse_url = parse_momo_short_url(destination_url) if destination_url: print(f"The destination URL for {short_url} is: {destination_url}") print(f"Parsed goodsUrl: {parse_url}") else: print(f"Could not resolve {short_url}") -
Save and Run
將上方的 Code 儲存,這邊我存成
test-short-url-simple.py,你可以自定義名稱。並且在終端機執行
python3 test-short-url-simple.py執行結果如下:
