用Python写一个本地Sogou代理服务器程序

真难以自信,使用Python强大的类库,可以用这么简短的代码就写好一个本地的HTTP代理!
真难以自信,这是我用Python花了连续6个小时写的第一个程序(之前写的一个Hello world除外)!
真难以自信,我就这样爱上了Python……
所以,以后在我博客上估计会有不少Python代码了……

现在我使用Python仍然停留在Thinking In The C++ Way而不是Thinking In The Python Way,所以最近会打算看一些Python类库里面的代码,看看别人是如何写的。

一开始使用Python3.2编写这个代理服务器,后来移植到Python2.7上去,这两个版本的差异还真的挺大的,我记得移植的时候改了不少地方。
我用py2exe编译了不需要Python运行环境的Windows可执行文件版本,方便大家测试,貌似编译之后比较臃肿。

这里有一篇关于如何使用py2exe编译python脚本的文章:
www.cnblogs.com/jans2002/archive/2006/09/30/519393.html

下载地址:sogouproxy win32

Python源代码:

'''
    Hey guys!
    This is a the first python program(except hello worlds) I have written. 
    With HTTPServer, I can easily write a webserver.
    Python is such a powerful language that many complicated problems can be
    solved by a few lines of code.

    Welcome to visit my blog: www.xiaoxia.org
    The proxy program is just coded for fun :-)
'''

from threading import Thread
from struct import unpack
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from httplib import HTTPResponse
from SocketServer import ThreadingMixIn
import socket
import time, sys, random

x_sogou_auth = "9CD285F1E7ADB0BD403C22AD1D545F40/30/853edc6d49ba4e27"
proxy_host = "h0.cnc.bj.ie.sogou.com"
proxy_port = 80

def calc_sogou_hash(t, host):
    s = (t + host + 'SogouExplorerProxy').encode('ascii')
    code = len(s)
    dwords = int(len(s)/4)
    rest = len(s) % 4
    v = unpack(str(dwords) + 'i'+str(rest)+'s', s)
    for vv in v:
        if(type(vv)==type('i')):
            break
        a = (vv & 0xFFFF)
        b = (vv >> 16)
        code += a
        code = code ^ (((code<<5)^b) << 0xb)
        # To avoid overflows
        code &= 0xffffffff
        code += code >> 0xb
    if rest == 3:
        code += ord(s[len(s)-2]) * 256 + ord(s[len(s)-3])
        code = code ^ ((code ^ (ord(s[len(s)-1])*4)) << 0x10)
        code &= 0xffffffff
        code += code >> 0xb
    elif rest == 2:
        code += ord(s[len(s)-1]) * 256 + ord(s[len(s)-2])
        code ^= code << 0xb
        code &= 0xffffffff
        code += code >> 0x11
    elif rest == 1:
        code += ord(s[len(s)-1])
        code ^= code << 0xa
        code &= 0xffffffff
        code += code >> 0x1
    code ^= code * 8
    code &= 0xffffffff
    code += code >> 5
    code ^= code << 4
    code = code & 0xffffffff
    code += code >> 0x11
    code ^= code << 0x19
    code = code & 0xffffffff
    code += code >> 6
    code = code & 0xffffffff
    return hex(code)[2:].rstrip('L').zfill(8)

class Handler(BaseHTTPRequestHandler):
    s = 0
    def do_proxy(self):
        try:
            if self.s == 0:
                self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.s.connect((proxy_host, proxy_port))
            self.s.send(self.requestline.encode('ascii') + b"\r\n")
            # Add Sogou Verification Tags
            self.headers["X-Sogou-Auth"] = x_sogou_auth
            t = hex(int(time.time()))[2:].rstrip('L').zfill(8)
            self.headers["X-Sogou-Tag"] = calc_sogou_hash(t, self.headers['Host'])
            self.headers["X-Sogou-Timestamp"] = t
            self.s.send(str(self.headers).encode('ascii') + b"\r\n")
            # Send Post data
            if(self.command=='POST'):
                self.s.send(self.rfile.read(int(self.headers['Content-Length'])))
            response = HTTPResponse(self.s, method=self.command, buffering=True)
            response.begin()
            # Reply to the browser
            status = "HTTP/1.1 " + str(response.status) + " " + response.reason
            self.wfile.write(status.encode('ascii') + b'\r\n')
            h = ''
            for hh, vv in response.getheaders():
                if hh.upper()!='TRANSFER-ENCODING':
                    h += hh + ': ' + vv + '\r\n'
            self.wfile.write(h.encode('ascii') + b'\r\n')
            while True:
                response_data = response.read(8192)
                if(len(response_data) == 0):
                    break
                self.wfile.write(response_data)
        except socket.error:
            print('socket error for ' + self.requestline)
    def do_POST(self):
        self.do_proxy()
    def do_GET(self):
        self.do_proxy()

class ThreadingHTTPServer(ThreadingMixIn, HTTPServer):
    pass

server = ThreadingHTTPServer(("127.0.0.1", 1998), Handler)

#print(calc_sogou_hash('4d8cdaed', 'www.youku.com'))

print('Please select your network:\n\
      1. CERNET(The China Education and Research Network)\n\
      2. CTCNET(China Telecommunications Corporation)\n\
      3. CNCNET(China NetCom)\n\
      4. DXT(Dian Xin Tong)\n')
i = int(input('Input the number: '))
if i==1:
    proxy_host = 'h' + str(random.randint(0,10)) + '.edu.bj.ie.sogou.com'
elif i==2:
    proxy_host = 'h' + str(random.randint(0,3)) + '.ctc.bj.ie.sogou.com'
elif i==3:
    proxy_host = 'h' + str(random.randint(0,3)) + '.cnc.bj.ie.sogou.com'
elif i==4:
    proxy_host = 'h' + str(random.randint(0,10)) + '.dxt.bj.ie.sogou.com'

print('Proxy over ' + proxy_host)
server.serve_forever()

用Python写一个本地Sogou代理服务器程序》有39个想法

  1. whitefirer

    又多了个pythoner~~……像你原来提到过的notify用python的话就几行

    另,我觉得最后那段写到main里会好些

    回复
    1. Xiaoxia 文章作者

      官方有库的手册,网上也有很多实例代码,用起来还是挺方便的。
      而且,我也经常去翻库函数的代码看,看一下它的代码实现就更好了。
      Python的标准库的代码阅读起来很爽,比起C++的STL代码,更好看,更易懂啊!

      回复
            1. Xiaoxia 文章作者

              好像就是IE core的浏览器看不了Python的代码!!!
              哈哈,要看代码,大家都用Firefox或者Chrome吧……

              回复
  2. Mike Ma

    表示fedora的yum就是用python写的……
    个人虽然喜欢python,但是还是喜欢c/vala 更多吧(对解释型无爱)
    写代理服务器应该性能要求更大吧

    回复
    1. Xiaoxia 文章作者

      对,如果要做出产品给用户使用的话,为了满足性能上的需求,还是C/C++比较实际。
      Python方便我写测试代码。

      回复
  3. r2ddrr2

    楼主,你的软件编的真的很好啊。有一个问题,为什么用了你的代理后,打不开qq邮箱之类的?

    回复
  4. 真难以置信,我想在linux下不用wine使用sogou代理的多年夙愿就这样实现了!
    真难以置信,还是用我最爱的python写的!
    真难以置信,楼主还是hello world之后就写了这个!!!
    …果断订阅小虾的rss!!

    泪流满面,妈妈再也不用担心我在教育网下用linux和mac os x上不了各种网站了…谢谢谢谢楼主!!!

    回复
        1. Xiaoxia 文章作者

          你怎么运行的呀?
          例如保存为proxy.py。
          在终端里,输入
          [email protected]:~# python proxy.py 回车。

          显示如下:
          [email protected]:~# python proxy.py
          Please select your network:
          1. CERNET(The China Education and Research Network)
          2. CTCNET(China Telecommunications Corporation)
          3. CNCNET(China NetCom)
          4. DXT(Dian Xin Tong)

          Input the number: 1
          Proxy over h3.edu.bj.ie.sogou.com

          回复
  5. Pingback引用通告: Python写简单的网络服务器示例 « Xiaoxia[PG]

  6. Pingback引用通告: Linux下独立使用搜狗浏览器代理 | Ernest's Blog

    1. Xiaoxia 文章作者

      登录用到了https了吧!!!我周一或周二发一个完美支持https的sogou代理版本,关注我的文章哈哈。

      回复
  7. Pingback引用通告: 用Python写的本地Sogou代理服务器程序 | 核桃薄壳

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据