自动采集免费 SS 服务器的密码,使用 Shadowsocks 翻墙。
来源: 关于科学上网两三事-续
前言
在上篇文章中我们介绍了市面上几种番羽土啬的方式,以及如何搭建一套属于自己SS服务端,但是考虑到多种原因,很多小伙伴应该也不会那么做。
为啥咧?你们都去打农药了吗?你们都去约会了吗?说的跟你们真的有女朋友似得。
今天我们不聊这个,我们今天就是要帮懒人做件事,话说懒人番羽土啬要干嘛?
那我猜肯定是倒数第三种。
那我猜肯定是倒数第三种。
有什么问题吗?
上篇文章问题提到如何搭建自己的ss服务器,很多小伙伴提到自己搭建太麻烦,费用也是个问题
但是,你还记得上一篇文章的最后,提到一个免费的代理账号的网站,但是周围很多小伙伴还是说使用起来太不方便了。
纳尼?
- 网站上有多个账号数据,有很多个不能使用,一次次填写账号密码数据太繁琐。
- 代理账号密码数据每6个小时更新一次,更新后原账号密码数据不可用,难道我要每6个小时再重复上面的动作?
仔细想了想,确实是这个样子,每次都要做重复的操作确实太不软件工程了,那么,那么就让我们洗洗睡吧。
开什么玩笑,问题肯定要解决啊。
唠唠这些问题
上一节我们提到要实现这么一个工具(软件)来获取网站上的账号和密码数据到保存到本地并配置给代理软件。
1.咦,账号的获取
首先我们说说怎么获取这些账号和密码数据,肯定不能再一次次手动打开这个网站去抄这些数据吧,爬虫在这个时候就显得非常好用了。
那么,该用什么来实现这个爬虫呢?
这里我采用了Jsoup来显示这个爬虫,主要是因为python的定时调度不好用(下面具体说明)
使用jsoup爬去这个页面的数据和python一样,写起来很简单
public List<SSBean> getSSAccount() {
Document document = null;
try {
document = Jsoup.connect("http://ss.ishadowx.com/").get();
Element firstElement = document.getElementsByClass("portfolio-items").first();
Elements ssElements = firstElement.getElementsByClass("hover-text");
for (Element element : ssElements) {
SSBean ssBean = new SSBean();
String address = element.getElementsByTag("h4").first().getElementsByTag("span").text();
String password = element.getElementsByTag("h4").get(2).getElementsByTag("span").first().text();
String portString = element.getElementsByTag("h4").get(1).text();
String port = portString.split(":")[1];
String methodString = element.getElementsByTag("h4").get(3).text();
String method = methodString.split(":")[1];
ssBean.setAddress(address);
ssBean.setPort(port);
ssBean.setPassword(password);
ssBean.setMethod(method);
if (ssBean.getPassword() == null || ssBean.getPassword().isEmpty()) {
continue;
}
ssBeanList.add(ssBean);
}
} catch (IOException e) {
e.printStackTrace();
}
return ssBeanList;
}
运行程序,我们便得到了这个List的账号数据
是的,我们通过很简单的代码便获取到了这些账号数据,但是这些数据我们该怎么用呢?直接生成文件保存本地?每次使用都需要从网站去爬去这些数据?这些数据如何配置到SS?
停,停……
我已经不敢往下继续想了。
2.啊,我的思路呢
别闹,问题还是需要解决的。刚才我们使用很简单的代码获取到了网站上的账号数据,但是……
需要我给翻译吗?
相信我,这不是网站自带的功能,真的是我翻译的,才怪。。。
也就是说,网站上的数据每6个小时更新一次,我们一次性抓取保存时没有用的,因为你下次用的时候他说不定已经过期了,你肯定回想那我就不存了啊,我有空了就去启动我的软件,或者我就在上面的时间段后去运行这段代码,好吧你真的不懒,是很闲啊。
- 第一,我们的爬取代码肯定不能放在客户端,网站页面有访问限制,多次访问会被封ip(又是防抓取套路……)
- 第二,抓取代码需要定期执行,去自动抓取
- 第三,程序放在服务端将爬取的数据放在数据库,需要提供接口支持
在上面提到我们没有使用python,因为python定时调度不好管理,而且接口部署没有java的spring boot这么简单。
下面就讲讲服务端的实现。
3.呀,服务端
既然服务端只是简单的接口实现和数据库存取操作,那么Spring boot肯定是首选啊,Spring boot在做微服务方面还是很方便的。
页面爬去入库
在model层实现对页面的爬去,在Controller层调用爬去方法定期执行,并提数据库查询接口。
@Component
public class ScheduledTasks {
@Autowired
private SSRespository ssRespository;
private static final Logger log = LoggerFactory.getLogger(ScheduledTasks.class);
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
SSAccountModel ssAccountModel;
@Scheduled(cron = "0 0/15 0,6,12,18 * * *" )
public void reportCurrentTime() {
log.info("The time is now {}", dateFormat.format(new Date()));
ssAccountModel = new SSAccountModelImpl();
List<SSBean> ssAccount = ssAccountModel.getSSAccount();
if (ssAccount == null || ssAccount.size() == 0) {
log.info("爬取得信息:{}", "爬取失败");
} else {
log.info("爬取得信息:{}", ssAccount.toString());
ssRespository.deleteAll();
ssRespository.save(ssAccount);
}
}
}
使用@Scheduled(cron = “0 0/15 0,6,12,18 *” )注解实现程序在每天的0:15,6:15,12:15,18:15定期执行。
ssRespository.deleteAll();
ssRespository.save(ssAccount);
如上代码,在插入数据库前清空数据库并插入,这样就实现了定期对网站页面的爬去和入库操作
接口映射
有了数据给客户端提供接口就显得很简单了,直接从数据库查询数据返回给调用者即可,当然这里没有对调用者做限制,主要演示实现。
@RestController
public class SSCountController {
@Autowired
private SSRespository ssRespository;
@RequestMapping("/getAccount")
public Iterable<SSBean> getSSAccount() {
Iterable<SSBean> all = ssRespository.findAll();
return all;
}
}
运行程序,在浏览器访问 http://localhost:8080/getAccount 即可。
4.嗨,客户端
由于考虑到在客户端(window)运行,考虑到没有安装jdk环境的,所以不能使用java打jar包实现,由于客户端的业务很简单,主要就是调用接口生成配置文件,打开SS客户端完成配置文件的加载。
考虑到生成exe文件,这里客户端就直接使用python来实现了
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# --------------------------
# Author fzl
# Date 2017/7/20 15:13
# EMAIL fangjalylong@qq.com
# Desc
# --------------------------
import json
import requests
import sys
from ExeUtil import ExeUtil
type = sys.getfilesystemencoding()
print( "***************************************************************")
print( "* *").decode('utf-8').encode(type)
print( "*******************欢迎使用免费代理更新程序********************").decode('utf-8').encode(type)
print( "* *").decode('utf-8').encode(type)
print( "*******************正在更新配置文件,请稍后********************").decode('utf-8').encode(type)
print( "* *").decode('utf-8').encode(type)
print( "***************************************************************")
url = 'http://121.42.170.72:8080/Shadowsocks/getAccount'
data = requests.get(url)
beans=json.loads(data.text)
file=open("gui-config.json","w+")
file.write('''{
"configs": ['''+'\n')
for index in range(len(beans)):
file.writelines('{')
file.write('''"server": "'''+beans[index]['address'].strip()+'''"'''+',\n')
file.write('''"server_port": "'''+beans[index]['port'].strip()+'''"'''+',\n')
file.write('''"password": "'''+beans[index]['password'].strip()+'''"'''+',\n')
file.write('''"method": "'''+beans[index]['method'].strip()+'''"'''+',\n')
file.write('''"remarks": "'''+beans[index]['address'].strip()+'''"'''+',\n')
file.write('''"timeout": "'''+'5'+'''"'''+'\n')
if index==len(beans)-1:
file.writelines('}')
else:
file.writelines('},')
file.write(''' ],
"strategy": null,
"index": 0,
"global": true,
"enabled": false,
"shareOverLan": true,
"isDefault": false,
"localPort": 1080,
"pacUrl": null,
"useOnlinePac": false,
"secureLocalPac": true,
"availabilityStatistics": false,
"autoCheckUpdate": true,
"checkPreRelease": false,
"isVerboseLogging": true,
"logViewer": {
"topMost": false,
"wrapText": true,
"toolbarShown": false,
"Font": "Consolas, 8pt",
"BackgroundColor": "Black",
"TextColor": "White"
},
"proxy": {
"useProxy": false,
"proxyType": 0,
"proxyServer": "",
"proxyPort": 0,
"proxyTimeout": 3
},
"hotkey": {
"SwitchSystemProxy": "",
"SwitchSystemProxyMode": "",
"SwitchAllowLan": "",
"ShowLogs": "",
"ServerMoveUp": "",
"ServerMoveDown": ""
}
}''')
file.close()
print( "* *").decode('utf-8').encode(type)
print( "* SS默认选中第一个代理账号,如不可用请尝试切换其他账号 *").decode('utf-8').encode(type)
print( "* *").decode('utf-8').encode(type)
print( "* *").decode('utf-8').encode(type)
print( "* 配置文件已经更新,Shadowsocks已经启动 *").decode('utf-8').encode(type)
print( "* *").decode('utf-8').encode(type)
print( "* *").decode('utf-8').encode(type)
print( "* by:flyou *").decode('utf-8').encode(type)
print( "* *").decode('utf-8').encode(type)
print( "* http://www.flyou.ren *").decode('utf-8').encode(type)
print( "* *").decode('utf-8').encode(type)
print( "***************************************************************")
exeUtil=ExeUtil('.','Shadowsocks.exe')
exeUtil.openExe()
打开exe工具类
class ExeUtil:
def __init__(self, filePath, fileName):
self.filePath = filePath
self.fileName = fileName
def openExe(self):
try :
handle = win32process.CreateProcess(os.path.join(self.filePath, self.fileName),
'', None, None, 0,
win32process.CREATE_NO_WINDOW,
None ,
self.filePath,
win32process.STARTUPINFO())
running = True
except Exception, e:
print "Create Error!"
handle = None
running = False
while running :
rc = win32event.WaitForSingleObject(handle[0], 1000)
if rc == win32event.WAIT_OBJECT_0:
running = False
#end while
print "GoodBye"
5.哈 ,试一试效果
执行代码,即可完成配置文件的生成和装载
此时,Shadowsocks应用就会已经启动(目录下需要有Shadowsocks)并成功加载相应的账号配置,如下图
浏览器如何配置代理请参照上一篇文章
注意,抓取的账号不是每一个都可以用,但是至少有3、4个是很快的,右键点击ss尝试切换不同的账号吧。
NOW,DO WHAT YOU WANT TO DO
最后还要唠叨几句
说了这么多,你的安装文件呢?哎呀,只顾着学习(装逼)忘记留种了%^……^%
关于软件的使用说明:
1.解压FreeShadowsocks.rar到任意目录2.点击FreeShadowsocks.exe邮件发送到桌面快捷方式3.点击桌面快捷方式即可打开程序。备注:本软件只是定时获取网络上可用的SS账号数据并下发配置文件到本地如果发现账号不可用请切换到其他代理账号重试或者退出SS重新打开本软件原则上账号数据会每6个小时更新一次服务器会在每天的0:15,6:15,12:15和18:15去重新生成相应账号请务必在此时段重新打开本软件已获取最新的账号数据,以保证正常使用代理
没有评论:
发表评论