一日一技:在Scrapy中如何拼接URL Query参数?

我们知道,在使用Requests发起GET请求时,可以通过params参数来传递URL参数,让Requests在背后帮你把URL拼接完整。例如下面这段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 实际需要请求的url参数为:
# https://www.kingname.info/article?id=1&doc=2&xx=3

import requests

params = {
'id': '1',
'doc': '2',
'xx': '3'
}

requests.get('https://www.kingname.info/article', params=params)

那么在Scrapy中,发起GET请求时,应该怎么写才能实现这种效果呢?

我知道很多同学是通过字符串的format操作来拼接URL的:

1
2
3
4
5
6
7
8
url_template = 'https://www.kingname.info/article?id={id}&doc={doc}&xx={xx}'
params = {
'id': '1',
'doc': '2',
'xx': '3'
}

url = url_template.format(**params)

但实际上,Scrapy的FormRequest不仅能用来发起POST请求,还可以在GET请求的时候用来拼接参数。它的写法为:

1
2
3
4
5
6
7
params = {
'id': '1',
'doc': '2',
'xx': '3'
}

yield scrapy.FormRequest('https://www.kingname.info/article', formdata=params, method='GET')

这只是一个小技巧。大家可以自由选择是使用这种方法还是使用字符串的format填充。

不过话说回来,我想起以前遇到过一个网站,他们的反爬虫方法非常巧妙。

在正常情况下URL的参数顺序是没有任何关系的,什么顺序都可以。但这个网站反爬虫的机制,其中一个环节会判断这些参数在URL中的顺序。例如写成https://www.kingname.info/article?id=1&doc=2&xx=3就一切正常,但写成https://www.kingname.info/article?doc=2&id=1&xx=3就无法访问。当我们无论使用Requests的params参数,还是使用Scrapy的FormRequest参数,它自动组装的参数一般都是字典序,会按参数的首字母顺序排序。但这个网站需要的参数顺序刚好不是字典序,于是网站就会发现你。