迫于种种原因,有时候我们不得不做一些流量转发的操作。
比如写爬虫。
写爬虫时,时常要与目标网站的“运维”、“程序员”斗智斗勇,而“代理”作为行走江湖必备的入门级杀手锏,自然是要逢场必上。
有匪君子,如切如磋,如琢如磨。 有匪君子,如切如磋,如琢如磨。
而这个“杀手锏”是不是那么好用却与代理的数量、质量息息相关。
我时常苦恼于“维护代理”和“切换代理”的麻烦,我堂堂一代“爬虫大王”,冉冉升起的“东方新星”,万千少女的。。。呃,好像有点扯远了。总之,怎能沉溺于区区“代理切换”这种微不足道的小事中。
那么,如果可以用一个二级代理来封装这些事情岂不美哉!
所谓空想不如实干,不仅要实干,更要撸起袖子加油干!于是抓起 Python 就撸了一个流量转发程序。
程序不长,去掉空行只有 45 行,但完整的实现了流量转发的功能,基于 ssclient 实现了二级代理,完整代码如下:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
import select
from concurrent.futures import ThreadPoolExecutor
def process(conn, addr):
proxy_conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
proxy_conn.connect(('127.0.0.1', 1080))
conn.setblocking(socket.MSG_DONTWAIT)
proxy_conn.setblocking(socket.MSG_DONTWAIT)
closed = False
while not closed:
rlist, _, _ = select.select([conn, proxy_conn], [], [])
for r in rlist:
w = proxy_conn if r is conn else conn
try:
d = r.recv(1024)
if not d:
closed = True
break
w.sendall(d)
except:
closed = True
break
try:
proxy_conn.shutdown(socket.SHUT_RDWR)
proxy_conn.close()
except:
pass
try:
conn.shutdown(socket.SHUT_RDWR)
conn.close()
except:
pass
def start():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 1991))
s.listen(10)
pool = ThreadPoolExecutor(128)
print('Server listen on 0.0.0.0:1991')
while True:
conn, addr = s.accept()
pool.submit(process, conn, addr)
if __name__ == '__main__':
start()
流量转发既已实现,剩下的事情就很好解决了,无非是维护一个可用的“代理池”,在转发流量的过程中随机选取一个可用代理,之后进行流量转发即可。
完整的功能将在我开发完成之后在博客中跟大家分享,并同步发布到我的微信公众号上。有兴趣的朋友可以关注我的公众号哟~
本帖同步更新在我的博客上,原文在此。
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.