Chrome插件之ModHeader
一、ModHeader是什么
ModHeader顾名思义就是让我们可以自定义HTTP请求头或者是重写响应头,包括新增请求头/响应头或者覆盖Chrome浏览器设置的请求头的默认值,同时还可以根据URL Pattern来只对特定网站生效。
Request header用来定义请求头,Response header用来定义响应头,Filter用来设置针对特定网站生效:
二、在爬虫开发中的应用场景
2.1 爬取网站时的语言设置问题
为什么我需要这么一款看上去没啥用的插件呢?因为在实际的爬虫任务中碰到一个问题,要爬取的网站是个国外的网站,而现在稍具规模的网站都喜欢搞国际化,就是针对不同国家的访客显示不同的语言,理论上这样对用户更友好(实际上国际化如果做得不够好的话会有点奇怪...),这样就不用让用户再去找翻译软件翻译了,而且国际化是人设置的理论上要比翻译软件更好一些。
那国际化是通过什么实现的呢?HTTP请求头有一项叫做Accept-Language,就是用来向服务器声明应该优先给自己显示什么语言。Chrome浏览器在发送请求的时候会根据浏览器当前的语言偏好设置这个请求头的值:
比如我的浏览器设置如上图,然后请求时Chrome就会将Accept-Language设置成这样的:
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
目标网站虽然是外国网站,但是它接收到我的请求然后从请求头中拿出Accept-Language一看,呦,稀客呀,有zh-CN,说明访客要求优先查看简体中文,然后它就从配置好的一个国际化文件中取出中文的语言配置,这个配置文件简陋点的话就类似于这种:
cn.welcome=欢迎访问我们的网站 cn.vote=顶 cn.next_page=下一页 cn.previous_page=上一页
然后HTML页面上对应的位置都不直接写常量而是用一个变量来代替,变量就对应着上面这个配置文件中的键名去除cn.之后的部分,比如${vote},这样根据不同情况加载不同语言配置文件然后使用变量的值渲染页面就可以实现显示不同语言,但是理想很丰满,现实很骨感,上面这个配置文件并不一定能覆盖到页面中的所有变量,也就是说现在页面上有一个foo变量在上面的配置文件中找不到对应的中文值怎么办,总不能空着吧,算了就先拿默认语言英文顶一下吧,于是就出现了有坑爹的国际化一半中文一半英文。这对人来说当然无所谓,但是对于程序来说区别就很大了,如果在程序中手动设置Accept-Language的话,比如我手动设置了优先中文,那么很多东西都会变成我所熟悉的,举个例子比如数字的显示方式,在我们国家使用逗号做千位分隔符,使用点做小数分隔符,比如一千零一点一,在我们国家一般会写成成“1,001.1”,而在某些欧洲国家,正好是反着来的,它们使用逗号做小数分隔符,使用点做千位分隔符,就会写做“1.001,1”,乍一看是让人懵逼的(维基百科 - 小数点),同理还有对日期的显示,如果能将这些使用中国的方式显示,看起来和解析起来都会爽很多,可是它们这种迷之国际化页面中哪些是中文哪些是英文是不受我控制的,很有可能他们稍稍一改我的程序就挂了,或者某个关键字段之前是用英文显示的某一天突然变中文了...写代码时应该尽量减少不可控因素所占的比重,所以没有特殊情况的话,我们在爬取一个网站时使用的语言应该尽量是这个网站的默认语言,即不设置Accept-Language这个请求头即可。
但是另一个问题又来了(我勒个天跑题半天终于绕回来了),我程序中没有设置Accept-Language,然后我热心肠的Chrome浏览器帮我设置了Accept-Language,然后我在Chrome中使用开发者工具排查问题时看到的页面的语言就跟我程序中的不一致,如果调整Chrome的语言设置的话虽然能解决问题但是这个设置是全局的会对所有网站都有影响,搞不好我以后访问一个有国际化的中文网站,它一看我的Accept-Language是以en打头的二话不说返回给了我英文版的网站,我找谁说理去...这个时候终于轮到在门外站了半天的ModHeader出场了,使用ModHeader将Chrome浏览器的Accept-Language调整为和程序中的一致即可,即手动设置为想要的语言或置空,然后在URL Pattern只匹配目标网站,这样至少在浏览器中看到的语言和程序中是一致的,而且对访问其它站点也没有影响,也算是爬取国外网站调试的一个小技巧吧。
最后解释一下为什么国际化使用Accept-Language而不是基于IP做判别,因为基于IP的话容易误判,比如挂了代理,比如肉身翻~墙(竟然会被判定为敏感字没想到博客园也搞这一套...)想使用母语等情况,而Accept-Language一般都是浏览器设置的,浏览器更知道当前的系统环境应该是哪种语言在安装时就可以自动设置为正确的语言,然后又提供了修改途径来让用户可以手动修正,这种方式更可靠。
2.2 借助ModHeader来检测必须要设置的请求头
很多网站都会有简单的反爬措施,比较常见的是加密参数,加密参数的其中一种形式是使用自定义的请求头来设置,比如下面这个请求头:
:authority: api.joom.com :method: GET :path: /1.1/products/1498834929187697429-213-1-709-71790600/sizeTables?currency=USD&language=en-US&_=joaauqxc :scheme: https accept: */* accept-encoding: gzip, deflate, br accept-language: zh-CN,zh;q=0.9,en;q=0.8 authorization: Bearer SEV0001MTU0MTc0ODc0N3xoSjZTMmF4TFp0MVZrQkgwcXc4X3cwVGRiX0dseFM0RjRVZS04Nk1Benl1X01YSHZKb3loSEFYT2IzQUVXOXdvRDJuSktScW4zbUpQd0tYTHlkendxQU9VdWZjSUVQVEJROGNGSW9qMFdUNHJpdllfUXlmd2NteVYxUVFaMUc3VS1mNk8yZXoxTnhuTWs4S1VVdTV2bU5xeExBZzlhMjZqTmpWdkRQc0FjbWVpMDFNPXz8wew7uOVGWgeKLikgiRVDi4EmSZ3N2dmd-5sz1ZKJDg== origin: https://www.joom.com referer: https://www.joom.com/en/products/1498834929187697429-213-1-709-71790600?context=%7B%22type%22%3A%22product%22%2C%22value%22%3A%5B%7B%22id%22%3A%221498834929187697429-213-1-709-71790600%22%2C%22type%22%3A%22pg%22%2C%22data%22%3A%22y8uHh4eH%2BflmZgEBAAAAAO1HA4bkpTdGfDfwd76maex7tY%2BDeOsoQUhHQ7m2bGbcRnL8SepQJnnjmW%2B10ic5dGbC4wTPTC6G%2FdUSDzg9vvCpZbGGn0A9FvtSYWiLaNQDYhLKWRek418JZf6%2FPEoE4uZrORmz2FOLRVs8jawo0mOraVj7rNDBuV5zDpWydGl4sCqPbnyg4zpOuTc%2FM418b4ysw%2BflK73seqQVTEKL4wf1J7sS8PX6EC%2Bpz3QhJdFzxIZc7jcjd%2BtWupz56QyQ53V4tyHQH0c%2Bu7tMzGXLkfnEC8je6m4tjnpJzuwV%2Frb%2FxFSyas0dJ73s%2BgFBPnLHnDdj9vDqklT3iEf2F8GCKBVK48lY8AWNcv%2B0kNzAprv6cXnXfH%2Fu0B0kbrEy4BRIr3Kh5lgbtkI6hU%2FXmwsRPYAWR9FVlTsLNQelBHe0yfRYz5rZhuRLd69n8q%2BKSdGPVXY58SWRmHxVtQDUxFCgqQQnMJX3DtnN1adOarhUzlEp%22%7D%5D%7D&contextSeed=1nk09 user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36 x-api-token: Uq4BiAM0c5yL22uuODvHe7GkBYSIDfVv x-ostype: Windows x-version: 0.1.15
其中的两个参数x-api-token和authorization看上去很可疑,怎么快速确定哪个请求头是必须要设置的呢?我们可不想花费太多时间在非必要参数上,当然可以写点代码一点一点测试出来,好,现在来将难度再升级一下,假如这些参数都是动态生成的,每次都不一样,即使将它们的值复制到程序中也不能用,也就是要在程序中模拟必须要先搞清楚这些值是如何来的,可是又不想花半天时间好不容易搞清楚一个请求头怎么来的突然发现这个请求头不设置也可以,只好在心里默默流泪... (╥╯^╰╥)
首先屏蔽掉x-api-token这个请求头:
然后刷新网页,观察请求数据的那个ajax请求的请求头:
x-api-token这个请求头没有设置依然返回了数据,说明它应该不是必要参数,不必再在这上面花费力气了。
再来试一下authorization:
清除缓存刷新:
不传这个参数页面直接挂掉了,连去请求商品详情的ajax请求都没有发送,说明这个参数应该是必须的,可使用同样方法排查其它请求头。
总结:使用ModHeader快速确定哪些请求头是必须的,提高分析目标网站的效率。
.