爬虫养成记 - 网络下载器urllib2伪装术

码海映月使
• 阅读 6182

前一个教程我们涉及到了urllib2的一些高级应用。这一片文章我们来比较系统的介绍一下。

该篇教程参考了静觅的博文:http://cuiqingcai.com/954.html
写这篇文章的目的仅仅是加深自己的印象。

Header

很多网站对我们用urllib2发起的请求进行辨别,所以我们需要对我们的请求做一定的伪装。

我打开一个Chrome开发者工具的Network Tab。

查看一个Request Headers

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4
Cache-Control:max-age=0
Connection:keep-alive
Cookie:__jsluid=237f8e30a392dd2dc08dda3c008b89bc; editor-code-detect-disabled=1; PHPSESSID=web1~1f6bt88ejrrdj2mgchjgfhi3c5; _gat=1; _ga=GA1.2.1502881944.1485175337; Hm_lvt_e23800c454aa573c0ccb16b52665ac26=1485175337,1485352359,1485352371; Hm_lpvt_e23800c454aa573c0ccb16b52665ac26=1485610162; sf_remember=f464bd79380df4d3c64702ba71d500f2
DNT:1
Host:segmentfault.com
Referer:https://segmentfault.com/u/charliecharlie/articles
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36
  • Accept: 客户端可以响应的数据类型

  • Accept-Encoding: 客户端可以接受的编码类型

  • Accept-Language: 客户端可以允许的语言

  • Cache-Control: 如果制定了max-age=5,则访问过某一个连接5秒内,再访问则不会再请求服务器。

  • Connection: 如果指定keep-alive则客户端请求长链接。

  • Cookie: 指定Cookie

  • DNT: 即Do not Tack。 发送请求方不希望被跟踪。

  • Host: 即主机。在http 1.0的加强版和http 1.1中加入了Host行。用于区分同一个ip的不同域名。

  • Referer: 即该请求的来源

  • Upgrade_Insecure-Requests: 可以阅读https://segmentfault.com/q/10...了解详情。

  • User-Agent: 即发出请求的用户信息。

  • Content-Type: 在使用REST接口的时候,服务器会检查该值。用来确定HTTP Body内容该如何解析。主要的值有 application/xml application/json application/x-www-form-urlencoded等

上面对于爬虫比较重要的有User-Agent、Referer。
User-Agent主要用来将Python urllib2伪装成一个正常的浏览器。
Referer主要用来应对有些网站的防盗链措施,给Referer指定一个网址,就是告诉服务器该请求来自域名内的某一个页面。

import urllib2

url = "http://www.baidu.com"
headers = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36",
    "Referer": "http://www.baidu.com"
}
request = urllib2.Request(url, headers=headers)
response = urllib2.urlopen(request)
print response.read()

Proxy(代理)设置

上面我们将urllib2通过设置headers将自己伪装成一个正常的浏览器,但是如果我们频繁快速地访问某一个域名,那么服务器就会很快发现我们是一个爬虫,因为正常的一个用户不会如此频繁快速地访问一个网站。

那么,我们就得将自己伪装成好几个用户(IP). 这时候就需要用到代理。
urllib2 默认会使用环境变量 http_proxy 来设置 HTTP Proxy。
但是我们需要更加灵活的切换代理。我们用一个代理访问一段时间后,就需要切换到其他代理再访问。
我们可以给urllib2安装ProxyHandler。ProxyHandler需要传入一个字典。该字典:it must be a dictionary mapping protocol names to URLs of proxies. . 就是说key是网络协议名称,value是代理的url。
例如:

proxies = {
    "http":"http://some_proxy.com:8080",
    "https":"https://some_proxy.com:8080"
}

下面是一个示例代码,展示了如何使用ProxyHandler。

import urllib2

proxy_handler = urllib2.ProxyHandler(proxies={"http": "http://124.88.67.54:80"})

opener = urllib2.build_opener(proxy_handler)
urllib2.install_opener(opener)

response = urllib2.urlopen('http://www.baidu.com')
print response.getcode()

DELETE 和 PUT 函数

http协议有六种请求方法,get,head,put,delete,post,options。

  • GET 客户端发送一个请求来获取服务器的资源。 服务器返回一组headers和呈现数据(html、图片资源等)给客户端。

  • HEAD 客户端发送一个请求来获取服务器资源等头信息。服务器只headers信息但是不返回呈现数据。主要的应用场景是用于判断某一个资源是否存在。

  • PUT 客户端请求新增一个资源。PUT与POST类似,但是表单不支持PUT。另外PUT一般会明确指定资源存放的位置。例如"http://www.myblog.com/articles/2100"。意思是将现在提交的数据存放于articles下第2100篇。由于表单不支持PUT操作,很多框架则是在form表单中设置一个隐藏的input来标示该请求应该是PUT。
    <input type="hidden" name="_method" value="put" />

  • DELETE 请求删除某一个资源。

  • POST 向服务器提交数据。

  • OPTIONS 向服务器查询该链接支持哪些请求方法。

理论上urllib2只支持GET、POST方法。并不支持http的其他方法。通过源码可知,Request判断采用哪种请求方式是通过判断是否设置了data。

    def get_method(self):
        if self.has_data():
            return "POST"
        else:
            return "GET"

因此我们可以临时覆写request的get_method方法来更改请求方法。例如

request = urllib2.Request("http://www.baidu.com")
request.get_method = lambda: "PUT" # 用匿名函数覆写request的get_method方法。

response = urllib2.urlopen(request)
print response.info()
点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
4年前
SpringBoot学习:整合shiro自动登录功能(rememberMe记住我功能)
首先在shiro配置类中注入rememberMe管理器!复制代码(https://oscimg.oschina.net/oscnet/675f5689159acfa2c39c91f4df40a00ce0f.gif)/cookie对象;rememberMeCookie()方法是设置Cookie的生成模
Wesley13 Wesley13
4年前
Java爬虫之JSoup使用教程
title:Java爬虫之JSoup使用教程date:201812248:00:000800update:201812248:00:000800author:mecover:https://imgblog.csdnimg.cn/20181224144920712(https://www.oschin
Easter79 Easter79
4年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
4年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Easter79 Easter79
4年前
SpringBoot学习:整合shiro自动登录功能(rememberMe记住我功能)
首先在shiro配置类中注入rememberMe管理器!复制代码(https://oscimg.oschina.net/oscnet/675f5689159acfa2c39c91f4df40a00ce0f.gif)/cookie对象;rememberMeCookie()方法是设置Cookie的生成模
Stella981 Stella981
4年前
Docker 部署SpringBoot项目不香吗?
  公众号改版后文章乱序推荐,希望你可以点击上方“Java进阶架构师”,点击右上角,将我们设为★“星标”!这样才不会错过每日进阶架构文章呀。  !(http://dingyue.ws.126.net/2020/0920/b00fbfc7j00qgy5xy002kd200qo00hsg00it00cj.jpg)  2
Python进阶者 Python进阶者
2年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这