45 行 Python 代码实现 TCP 二级代理

2018-07-22 00:45:29 +08:00
 nozer

迫于种种原因,有时候我们不得不做一些流量转发的操作。

比如写爬虫。

写爬虫时,时常要与目标网站的“运维”、“程序员”斗智斗勇,而“代理”作为行走江湖必备的入门级杀手锏,自然是要逢场必上。

有匪君子,如切如磋,如琢如磨。 有匪君子,如切如磋,如琢如磨。

而这个“杀手锏”是不是那么好用却与代理的数量、质量息息相关。

我时常苦恼于“维护代理”和“切换代理”的麻烦,我堂堂一代“爬虫大王”,冉冉升起的“东方新星”,万千少女的。。。呃,好像有点扯远了。总之,怎能沉溺于区区“代理切换”这种微不足道的小事中。

那么,如果可以用一个二级代理来封装这些事情岂不美哉!

所谓空想不如实干,不仅要实干,更要撸起袖子加油干!于是抓起 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()
    

流量转发既已实现,剩下的事情就很好解决了,无非是维护一个可用的“代理池”,在转发流量的过程中随机选取一个可用代理,之后进行流量转发即可。

完整的功能将在我开发完成之后在博客中跟大家分享,并同步发布到我的微信公众号上。有兴趣的朋友可以关注我的公众号哟~

本帖同步更新在我的博客上,原文在此

6726 次点击
所在节点    Python
32 条回复
lance6716
2018-07-22 12:06:09 +08:00
@AngelCriss 经常有些半吊子水平的的人写博客,搞得我一搜东西中文博文基本没法看
congeec
2018-07-22 12:06:44 +08:00
楼主你这态度在这社区可不好混

其实用 nc 或 socat 也就一行
socat TCP-LISTEN:8080,fork,reuseaddr TCP:google.com:443
nozer
2018-07-22 12:32:04 +08:00
@aheadlead @congeec 咱们解决的不是同一个问题,我是要以此为基础随机选取代理,并不是仅仅做流量转发,流量转发只是前提,我在帖子里面也有描述(虽然比较啰嗦)。

关于态度问题,好好讨论问题的,我向来认真对待。在我的回复里面,凡是指出问题的、提出建议的,只要中肯我都接受,并确认后期采纳,其它的我也会给出解释。

其它的上来就奇奇怪怪的回答,我也只好回应一些奇奇怪怪的东西。

比如这位大神 @aheadlead 上来就说一些与帖子本身无关的东西,我以为真的是 NB 哄哄的大神,结果点开帖子集一看,全是口水,半点干货没有,纯粹就是杠,这种人,我也只好他进行一番批判。 毕竟,今天是周末嘛。
nozer
2018-07-22 12:33:21 +08:00
。。。上一篇回复 at 错了人,aheadlead 抱歉抱歉。



@aheadlead @congeec 咱们解决的不是同一个问题,我是要以此为基础随机选取代理,并不是仅仅做流量转发,流量转发只是前提,我在帖子里面也有描述(虽然比较啰嗦)。

关于态度问题,好好讨论问题的,我向来认真对待。在我的回复里面,凡是指出问题的、提出建议的,只要中肯我都接受,并确认后期采纳,其它的我也会给出解释。

其它的上来就奇奇怪怪的回答,我也只好回应一些奇奇怪怪的东西。

比如这位大神 @lance6716 上来就说一些与帖子本身无关的东西,我以为真的是 NB 哄哄的大神,结果点开帖子集一看,全是口水,半点干货没有,纯粹就是杠,这种人,我也只好他进行一番批判。 毕竟,今天是周末嘛。
AngelCriss
2018-07-22 12:34:06 +08:00
@nozer 其实你这帖子也没有干活。。
nozer
2018-07-22 12:40:25 +08:00
至于有没有干货,我的收藏提醒是很好的证明。

@AngelCriss 好像楼有点歪了,大家还是对代码本身提出批判吧。
AngelCriss
2018-07-22 12:44:16 +08:00
@nozer 我是看到标题进来的,一看很厉害的样子,然而看了代码,发现真是浪费时间,所以有了 1 楼的回复,说的比较隐晦而已。
至于代码,没啥好说的,即使不会 Python 的人稍微看点文档也能写出来。
你批评的那位只不过直白的说出来了而已。
lihongjie0209
2018-07-22 13:26:30 +08:00
@wwqgtxx #9 io 操作用 thread 没问题
lance6716
2018-07-22 18:09:37 +08:00
@nozer 为什么你会觉得干货体现在论坛上,应该是课程作业、论文和项目啊…最近写了一个期末作业是支持作业调度的 shell,前置知识是 apue 这本书和一点点编译原理。然而我也不觉得有什么值得发出来的,毕竟都有 bash 了,我这种小打小闹的也是给互联网填充辣鸡
Kilerd
2018-07-22 22:09:54 +08:00
现在的中文 IT 圈就充斥着这样大量的低级而且可能充满大量问题的博文,甚至还会用几十年前的技术来实现某一个功能。

更可笑的是,还存在着更大一群人乐于转载这些内容,对,不加任何分辨的那种。奇怪的是,他们在发布这些文章的时候,不会去 review 一下排版问题。

最荒诞的是,大量的人根本没有能力去区分这一类的文章。(我见过有人真的认认真真地把那些因为到处复制转载而导致代码无法正常显示的文章阅读了,认真地敲里面的代码。
nozer
2018-07-23 10:35:48 +08:00
@Kilerd 阁下大才,所谓细微之处见真章,阁下既然指出“排版问题”至少是看过帖子内容的。我又细看了一下帖子,虽然排版实在算不上高明,但原本就是这样排的,只不过其中多出一句与本帖无关的话确系不应该。这是我的的失误,不过帖子没法编辑,也只能放任不管了。想必阁下必是做事细心之人,这点的确值得我辈学习,我会在今后注意这个问题。

不过再看阁下其它语句,又实在令人遗憾。

首先,第一句就显得很低级“现在的中文 IT 圈就充斥着这样大量的低级而且可能充满大量问题的博文,甚至还会用几十年前的技术来实现某一个功能。 ”

阁下以上帝视角站在“中文 IT 圈”之外,先把自己摘出来,再不管三七二十一把对方说成整个圈子的“低级”,我辈“米粒之辉”自然不敢同阁下这种“日月之光”比肩,想必阁下也实战过许多项目,绝不是那种做仅仅做过几个练习 Demo 就目空一切之辈,必然是胸中沟壑万千,从来不会写出这种“低级”博文,否则亦不敢说出如此狂妄之言。

阁下还说了“可能充满大量问题的博文”,就此暴露了阁下并非就事论事而是借题发挥。先不论博文到底是不是真的有问题,老是用这种“不确定性词汇”就足以让人觉得阁下办事不牢,因为阁下仅仅是凭借自己的臆想就直接得出结论,至于是不是真的“可能充满大量问题”谁关心呢,我只要发泄一下就好,这是不成熟的表现。

阁下又说“用几十年前的技术来实现某一个功能”,不觉让人发笑。Python2 在 2000 年发布至今不过 18 年,让 python 走向兴盛的 2.7 版也不过是 2010 年发布,距今不过 8 年。用几十年来形容似乎有点夸张过头了吧?况且,代码中用到的 socket 和线程池不过是最基础的手段,不管是 C、java 都在大量使用,你可以说它历史悠久没有异步编程那么优雅,但你要说这玩意儿就不应该再出现在人世间,恕我不敢苟同。

然后,阁下还有一句“最荒诞的是,大量的人根本没有能力去区分这一类的文章。(我见过有人真的认认真真地把那些因为到处复制转载而导致代码无法正常显示的文章阅读了,认真地敲里面的代码。”

这话看似没有任何问题,有理有据,现实中也的确不缺乏这样的人。但放在此处也不过是暴露阁下发泄情绪的目的,因为阁下这话的前提就是站不足脚的。阁下首先就把本贴列为“胡乱转载,导致代码无法正常展示”的“这一类文章”,请问阁下,本帖的代码是否无法正常运行,是否有缺行少字?阁下这才是最荒诞的。



最后,本帖大量无关回复已经带领本帖偏离初衷,失去了讨论的意义,恕我不再进行任何答复。有异议者可以 email 我:daoye.aim#outlook.com


最最后,所谓“论坛”其核心在“论”,恳请诸位不要戾气滔天,诚挚讨论,有一说一有二说二,共建和谐。
zeiyso
2018-08-13 23:21:46 +08:00
socket.sendall( ) 和 non-blocking I/O 不能一起用的

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/473005

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX