网络安全(一):爬虫和反爬虫
- 前言
- 一、爬虫
- 二、反爬虫
前言 一、爬虫
我们的爬虫程序以一个固定的ip去访问目标网站,目标网站会发现这个固定的ip有大量的请求,会判定为爬虫,直接进行屏蔽。
提供一种思路:代理服务器,代理服务器能够将固定的ip变成随机的ip,去访问目标网站。
public class ipliProxyProvider implements ProxyProvider {
private Logger logger = Logger.getLogger(ipliProxyProvider.class);
private List proxyList = new ArrayList<>();
private volatile Map> siteProxysMap = new HashMap>();
private Object siteProxysMapLock = new Object();
//获取代理信息的地址
private String apiurl;
//用户名
private String username;
//密码
private String password;
private volatile static ipProxyProvider instance = null;
public ipProxyProvider(String apiurl, String username, String password) {
this.apiurl = apiurl;
this.username = username;
this.password = password;
this.init();
}
public static ipProxyProvider getInstance(String apiurl, String username, String password) {
if (instance == null) {
synchronized (ipProxyProvider.class) {
if (instance == null) {
instance = new ipProxyProvider(apiurl, username, password);
}
}
}
return instance;
}
private void init() {
try {
logger.info("get proxy");
String s = HttpsUtil.requestGet(this.apiurl);
logger.info(s);
if (StringUtil.isNotEmpty(s)) {
final JSONObject jsonObject = JSON.parseObject(s);
if (jsonObject == null) {
return;
}
final JSONObject data = jsonObject.getJSONObject("data");
if (data == null) {
return;
}
final JSONArray proxy_list = data.getJSONArray("proxy_list");
if (proxy_list == null && proxy_list.size() == 0) {
return;
}
List tempList = new ArrayList<>();
for (int i = 0; i < proxy_list.size(); i++) {
final String string = proxy_list.getString(i);
final String[] split = string.split(":");
proxyList.add(new Proxy(split[0], Integer.parseInt(split[1]), this.username, this.password));
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
private ArrayBlockingQueue get(String key) {
try {
ArrayBlockingQueue queue = siteProxysMap.get(key);
if (queue == null) {
synchronized (siteProxysMapLock) {
queue = siteProxysMap.get(key);
if (queue == null) {
ArrayBlockingQueue proxies = new ArrayBlockingQueue(proxyList.size());
for (Proxy proxy : proxyList) {
proxies.put(proxy);
}
siteProxysMap.put(key, proxies);
}
}
}
} catch (InterruptedException e) {
this.logger.error(e.getMessage(), e);
}
return siteProxysMap.get(key);
}
@Override
public void returnProxy(Proxy proxy, Page page, Task task) {
this.logger.info(proxy);
try {
String key = getKey(task);
this.get(key).put(proxy);
} catch (InterruptedException e) {
this.logger.error(e.getMessage(), e);
}
}
private String getKey(Task task) {
final String domain = task != null && task.getSite() != null ? task.getSite().getDomain() : null;
return StringUtil.isNotEmpty(domain) ? domain : KuaidailiProxyProvider.class.getName();
}
@Override
public Proxy getProxy(Task task) {
Proxy proxy = null;
try {
proxy = this.get(this.getKey(task)).take();
this.logger.info(proxy);
} catch (InterruptedException e) {
logger.error(e.getMessage(), e);
}
return proxy;
}
}
二、反爬虫
1.对爬虫客户端以一个固定的ip去访问网站,网站会发现这个固定的ip有大量的请求,会判定为爬虫,直接进行屏蔽。
2.对于一些重要的接口进行隐藏,比如电商软件的抢购接口,实现思路:每次点击秒杀按钮,先从服务器获取一个秒杀验证值(接口内判断是否到秒杀时间)。Redis以缓存用户ID和商品ID为Key,秒杀地址为Value缓存验证值
用户请求秒杀商品的时候,要带上秒杀验证值进行校验。
@Override
public int createVerifiedOrder(Integer sid, Integer userId, String verifyHash) throws Exception {
// 验证是否在抢购时间内
LOGGER.info("请自行验证是否在抢购时间内,假设此处验证成功");
// 验证hash值合法性
String hashKey = CacheKey.HASH_KEY.getKey() + "_" + sid + "_" + userId;
String verifyHashInRedis = stringRedisTemplate.opsForValue().get(hashKey);
if (!verifyHash.equals(verifyHashInRedis)) {
throw new Exception("hash值与Redis中不符合");
}
LOGGER.info("验证hash值合法性成功");
// 检查用户合法性
User user = userMapper.selectByPrimaryKey(userId.longValue());
if (user == null) {
throw new Exception("用户不存在");
}
LOGGER.info("用户信息验证成功:[{}]", user.toString());
// 检查商品合法性
Stock stock = stockService.getStockById(sid);
if (stock == null) {
throw new Exception("商品不存在");
}
LOGGER.info("商品信息验证成功:[{}]", stock.toString());
//乐观锁更新库存
saleStockOptimistic(stock);
LOGGER.info("乐观锁更新库存成功");
//创建订单
createOrderWithUserInfo(stock, userId);
LOGGER.info("创建订单成功");
return stock.getCount() - (stock.getSale()+1);
}



