在我們寫爬蟲的時候,可能會需要在爬蟲里面基于當前url生成一個新的url。例如下面這段偽代碼:
- import re
- current_url = 'https://www.kingname.info/archives/page/2/'
- current_page = re.search('/(\d+)', current_url).group(1)
- next_page = int(current_page) + 1
- next_url = re.sub('\d+', str(next_page), current_url)
- make_request(next_url)
運行效果如下圖所示:
但有時候,翻頁參數不一定是數字。例如有些網站,訪問一個URL:https://xxx.com/articlelist?category=technology&after=asdrtJKSAZFD
當你訪問這個url的時候,它返回的是一個JSON字符串,并且這個JSON里面,有如下字段:
- ...
- "paging": {
- "cursors": {
- "before": "MTA3NDU0NDExNDEzNTgz",
- "after": "MTE4OTc5MjU0NDQ4NTkwMgZDZD"
- },
- }
- ...
這種情況多見于信息流網站。它只能無限下滑看下一頁,不能直接通過頁數跳頁。每次請求的時候返回下一頁的參數after。當要訪問下一頁的時候,用這個參數替換當前url中的after=后面的參數。
這樣一來,替換url中的參數就并不是一件簡單的事情了。因為網址可能有4種情況:
- 第一頁,沒有after參數:https://xxx.com/articlelist?category=technology
- 第一頁,有after參數名但沒有值:https://xxx.com/articlelist?category=technology&after=
- 后續頁面,after參數值后面沒有內容: https://xxx.com/articlelist?category=technology&after=asdrtJKSAZFD
- 后續頁面,aster參數值后面有內容:https://xxx.com/articlelist?category=technology&after=asdrtJKSAZFD&other=abc
大家可以試一試,如果用正則表達式,怎么覆蓋這4種情況,生成下一頁的網址。
實際上,我們不需要使用正則表達式。Python自帶的urllib模塊已經提供了解決這個問題的方案了。我們先來看一段代碼:
- from urllib.parse import urlparse, urlunparse, parse_qs, urlencode
- def replace_field(url, name, value):
- parse = urlparse(url)
- query = parse.query
- query_pair = parse_qs(query)
- query_pair[name] = value
- new_query = urlencode(query_pair, doseq=True)
- new_parse = parse._replace(query=new_query)
- next_page = urlunparse(new_parse)
- return next_page
- url_list = [
- 'https://xxx.com/articlelist?category=technology',
- 'https://xxx.com/articlelist?category=technology&after=',
- 'https://xxx.com/articlelist?category=technology&after=asdrtJKSAZFD',
- 'https://xxx.com/articlelist?category=technology&after=asdrtJKSAZFD&other=abc'
- ]
- for url in url_list:
- next_page = replace_field(url, 'after', '0000000')
- print(next_page)
運行效果如下圖所示:
從圖中可以看到,這4種情況,都可以被我們成功添加下一頁的參數after= 0000000。不用再去考慮正則表達式怎么適配所有情況。
其中urlparse 和urlunparse 是一對相反函數,前者把網址轉成 ParseResult 對象,后者把ParseResult對象轉回網址字符串。
ParseResult 對象的.query 屬性,是一個字符串,也就是網址中,問號后面的內容,格式如下:
parse_qs與urlencode也是一對相反函數。其中前者把 .query輸出的字符串轉成字典,而后者把字段轉成.query形式的字符串:
當使用parse_qs把 query轉成字典以后,就可以修改參數的值,然后再重新轉回去。
由于ParseResult對象的.query屬性是只讀屬性,不能覆蓋,因此我們需要調用一個內部方法._replace把新的.query字段替換上去,生成新的 ParseResult對象。最后再把它轉回網址。
以上,就是今天我們介紹的,如何使用urllib自帶的函數替換網址中的字段。
原文鏈接:https://mp.weixin.qq.com/s/ZwA9ZDBAuJopJXvCZIlxCw