3

python中如何自定义解析域名

 2 years ago
source link: https://www.hi-roy.com/posts/python%E4%B8%AD%E5%A6%82%E4%BD%95%E8%87%AA%E5%AE%9A%E4%B9%89%E8%A7%A3%E6%9E%90%E5%9F%9F%E5%90%8D/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

python中如何自定义解析域名

2013-11-01

最近要进行某网站的信息抓取工作,不过这个网站作出了一些限制:如果某IP过于频繁的访问则会把这个IP列入黑名单。

不过这个网站使用了CDN技术进行全球加速,那么访问时候只要在请求头中指定HOST,url中指定加速IP即可一定程度上缓解被封问题。

在网上找到一篇有关文章节选如下(原文链接http://www.hack0nair.me/?p=615):

第一种解决方案是利用http数据包头部中的“Host”属性。

在发送HTTP请求的时候,数据包的头部总是会带上各种各样的属性,比如Data、Referer、Cookie等。(Quick reference to HTTP headers)

其中的Host属性是指,当前访问资源对应的主机名和端口号。

假设我们要访问的url是 http://www.hack0nair.me/wp-admin/ ,需要域名固定解析为 127.0.0.1 这个IP。

使用python中urllib库的request做法是: urllib.request(url="http://127.0.0.1/wp-admin/", headers={"Host" : "www.hack0nair.me"}) 访问会产生如下的数据包:

GET http://127.0.0.1/wp-admin/ HTTP/1.1
Host: www.hack0nair.me
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:16.0) Gecko/20100101 Firefox/16.0
Accept: */*
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://www.hack0nair.me/

这样的访问会告诉127.0.0.1服务器,当前需要访问的/wp-admin是www.hack0nair.me这个域名的资源。

看来问题已经解决了,其实未必。

对于不需要cookie支持的访问来说,问题确实解决了。但如果是需要多次访问并要验证cookie的话,这样做是不行的。因为这样访问产生的cookie对应的作用域是IP而不是域名!于是就有了下面一种更完美的解决方案。


第二种解决方案是直接修改socket的address。 方法来自StackOverFlow的MattH:http://stackoverflow.com/questions/2236498/tell-urllib2-to-use-custom-dns

具体的意思是,建立HTTP连接的时候仍然使用域名,但是通过修改底层socket的address来达到目的。

这里理解起来需要一点计算机网络的基础。在建立HTTP连接的时候,在应用层必然会使用一个socket跟远方服务器进行通信,而socket建立的时候需 要指定服务器的地址,这时候我们只需要填入我们预设的IP地址即可。由于应用层是不会去关心它的底层如何建立连接的,它只知道自己正在对哪个域名进行访 问,这样就相当于“欺骗”了处于上层的HTTP服务。(我的语言表达能力略拙计的说= =)

大概就是上面这个意思了,那么要在python中实现上面的想法,首先需要建立一个httplib.HTTPConnection的子类,在里面定义一个 connect方法求修改socket.create_connection的默认参数;然后继承HTTPHandler这个类,重写里面的 http_open方法,使得http_open去调用第一步的子类;最后就是把HTTPHandler放到我们的opener里面。

MattH同时给出了HTTP和HTTPS的修改方案,不过我只要HTTP的修改就够了。下面是经过我修改的例子:

def MyHost(host):
  if host == 'www.hack0nair.me':
    return '127.0.0.1' # 指定的IP地址
  else:
    return host
class MyHTTPConnection(httplib.HTTPConnection):
  def connect(self):
    self.sock = socket.create_connection((MyHost(self.host),self.port),self.timeout)
class MyHTTPHandler(urllib2.HTTPHandler):
  def http_open(self,req):
    return self.do_open(MyHTTPConnection,req)
opener = urllib2.build_opener(MyHTTPHandler)
urllib2.install_opener(opener)
url = 'http://www.hack0nair.me/wp-admin'
req = request.Request(url)
req = f.read()

上面例子的含义是,当opener遇到域名是www.hack0nair.me时,MyHTTPHandler会让所建立的socket的address为指定的IP地址。由于没有对urllib相关对象进行修改,所以HTTP神马都不知道~

如果访问要带上cookie,那么还要加上HTTPCookieProcessor这个handler。


我使用第一种方式即解决了问题。对于需要登录的方式,我抓取的网站直接把从浏览器提取出来的COOKIE添加到请求头中即可实现登录访问,这个根据网站设置不同。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK