网页主动探测工具使用

单位的项目是IBatis做的,每个查询的SQL里面都有很多判断

  上次优化SQL之后,其中的一个分支报错,但是作为dba,不可能排查每一个分支.

  所以,干脆用爬虫爬过所有的网页,主动探测程序的异常.

  这样有两个好处

  1.可以主动查看网页是否异常 (500错误,404错误)

  2.可以筛查速度较慢的网页,从这个方向也可以定位慢SQL吧.(也有服务器资源不足,造成网络超时的情况)

  前提,

  必须是互联网公司,大多数网页不用登录也可以浏览

  首先,建表

  CREATE SEQUENCE seq_probe_id INCREMENT BY 1 START WITH 1 NOMAXvalue NOCYCLE CACHE 2000;

  create table probe(

  id int primary key,

  host varchar(40) not null,

  path varchar(500) not null,

  state int not null,

  taskTime int not null,

  type varchar(10) not null,

  createtime date default sysdate not null

  ) ;

  其中host是域名,path是网页的相对路径,state是HTTP状态码,taskTime是网页获取时间,单位是毫秒,type是类型(html,htm,jpg等)

  程序结构

  程序分三个主要步骤,再分别用三个队列实现生产者消费者模式.

  1.连接.根据连接队列的目标,使用Socket获取网页,然后放入解析队列

  2.解析.根据解析队列的内容,使用正则表达式获取该网页的合法连接,将其再放入连接队列.然后将解析的网页放入持久化队列

  3.持久化.将持久化队列的内容存入数据库,以便查询。

  程序使用三个步骤并行,每个步骤可以并发的方式.

但是通常来说,解析和持久化可以分别用单线程的方式执行.


import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.InputStreamReader;

import java.io.OutputStreamWriter;

import java.net.InetAddress;

import java.net.Socket;

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.SQLException;

import java.util.ArrayList;

import java.util.Iterator;

import java.util.List;

import java.util.Set;

import java.util.concurrent.BlockingQueue;

import java.util.concurrent.ConcurrentSkipListSet;

import java.util.concurrent.CopyOnWriteArrayList;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.LinkedBlockingQueue;

import java.util.concurrent.atomic.AtomicInteger;

import java.util.regex.Matcher;

import java.util.regex.Pattern;

public class Probe {

private static final BlockingQueue<Task> CONNECTLIST = new LinkedBlockingQueue<Task>();

private static final BlockingQueue<Task> PARSELIST = new LinkedBlockingQueue<Task>();

private static final BlockingQueue<Task> PERSISTENCELIST = new LinkedBlockingQueue<Task>();

private static ExecutorService CONNECTTHREADPOOL;

private static ExecutorService PARSETHREADPOOL;

private static ExecutorService PERSISTENCETHREADPOOL;

private static final List<String> DOMAINLIST = new CopyOnWriteArrayList<>();

static {

CONNECTTHREADPOOL = Executors.newFixedThreadPool(200);

PARSETHREADPOOL = Executors.newSingleThreadExecutor();

PERSISTENCETHREADPOOL = Executors.newFixedThreadPool(1);

DOMAINLIST.add("域名");

}

public static void main(String args[]) throws Exception {

long start = System.currentTimeMillis();

CONNECTLIST.put(new Task("域名", 80, "/static/index.html"));

for (int i = 0; i < 600; i++) {

CONNECTTHREADPOOL.submit(new ConnectHandler(CONNECTLIST, PARSELIST));

}

PARSETHREADPOOL.submit(new ParseHandler(CONNECTLIST, PARSELIST, PERSISTENCELIST, DOMAINLIST));

PERSISTENCETHREADPOOL.submit(new PersistenceHandler(PERSISTENCELIST));

while (true) {

Thread.sleep(1000);

long end = System.currentTimeMillis();

float interval = ((end - start) / 1000);

int connectTotal = ConnectHandler.GETCOUNT();

int parseTotal = ParseHandler.GETCOUNT();

int persistenceTotal = PersistenceHandler.GETCOUNT();

int connectps = Math.round(connectTotal / interval);

int parseps = Math.round(parseTotal / interval);

int persistenceps = Math.round(persistenceTotal / interval);

System.out.print("\r连接总数:" + connectTotal + " \t每秒连接:" + connectps + "\t连接队列剩余:" + CONNECTLIST.size()

+ " \t解析总数:" + parseTotal + " \t每秒解析:" + parseps + "\t解析队列剩余:" + PARSELIST.size() + " \t持久化总数:"

+ persistenceTotal + " \t每秒持久化:" + persistenceps + "\t持久化队列剩余:" + PERSISTENCELIST.size());

}

}

}

class Task {

public Task() {

}

public void init(String host, int port, String path) {

this.setCurrentPath(path);

this.host = host;

this.port = port;

}

public Task(String host, int port, String path) {

init(host, port, path);

}

private String host;

private int port;

private String currentPath;

private long taskTime;

private String type;

private String content;

private int state;

public int getState() {

return state;

}

public void setState(int state) {

this.state = state;

}

public String getCurrentPath() {

return currentPath;

}

public void setCurrentPath(String currentPath) {

this.currentPath = currentPath;

this.type = currentPath.substring(currentPath.indexOf(".") + 1,

currentPath.indexOf("?") != -1 ? currentPath.indexOf("?") : currentPath.length());

}

public long getTaskTime() {

return taskTime;

}

public void setTaskTime(long taskTime) {

this.taskTime = taskTime;

}

public String getType() {

return type;

}

public void setType(String type) {

this.type = type;

}

public String getHost() {

return host;

}

public int getPort() {

return port;

}

public String getContent() {

return content;

}

public void setContent(String content) {

this.content = content;

}

}

class ParseHandler implements Runnable {

private static Set<String> SET = new ConcurrentSkipListSet<String>();

public static int GETCOUNT() {

return COUNT.get();

}

private static final AtomicInteger COUNT = new AtomicInteger();

private BlockingQueue<Task> connectlist;

private BlockingQueue<Task> parselist;

private BlockingQueue<Task> persistencelist;

List<String> domainlist;


private interface Filter {

void doFilter(Task fatherTask, Task newTask, String path, Filter chain);

}

private class FilterChain implements Filter {

private List<Filter> list = new ArrayList<Filter>();

{

addFilter(new TwoLevel());

addFilter(new OneLevel());

addFilter(new FullPath());

addFilter(new Root());

addFilter(new Default());

}

private void addFilter(Filter filter) {

list.add(filter);

}

private Iterator<Filter> it = list.iterator();

@Override

public void doFilter(Task fatherTask, Task newTask, String path, Filter chain) {

if (it.hasNext()) {

it.next().doFilter(fatherTask, newTask, path, chain);

}

}

}

private class TwoLevel implements Filter {

@Override

public void doFilter(Task fatherTask, Task newTask, String path, Filter chain) {

if (path.startsWith("../../")) {

String prefix = getPrefix(fatherTask.getCurrentPath(), 3);

newTask.init(fatherTask.getHost(), fatherTask.getPort(), path.replace("../../", prefix));

} else {

chain.doFilter(fatherTask, newTask, path, chain);

}

}

}

private class OneLevel implements Filter {

@Override

public void doFilter(Task fatherTask, Task newTask, String path, Filter chain) {

if (path.startsWith("../")) {

String prefix = getPrefix(fatherTask.getCurrentPath(), 2);

newTask.init(fatherTask.getHost(), fatherTask.getPort(), path.replace("../", prefix));

} else {

chain.doFilter(fatherTask, newTask, path, chain);

}

}

}

private class FullPath implements Filter {

@Override

public void doFilter(Task fatherTask, Task newTask, String path, Filter chain) {

if (path.startsWith("http://")) {

Iterator<String> it = domainlist.iterator();

boolean flag = false;

while (it.hasNext()) {

String domain = it.next();

if (path.startsWith("http://" + domain + "/")) {

newTask.init(domain, fatherTask.getPort(), path.replace("http://" + domain + "/", "/"));

flag = true;

break;

}

}

if (!flag) {

newTask = null;

}

} else {

chain.doFilter(fatherTask, newTask, path, chain);

}

}

}

private class Root implements Filter {

@Override

public void doFilter(Task fatherTask, Task newTask, String path, Filter chain) {

if (path.startsWith("/")) {

newTask.init(fatherTask.getHost(), fatherTask.getPort(), path);

} else {

chain.doFilter(fatherTask, newTask, path, chain);

}

}

}

private class Default implements Filter {

@Override

public void doFilter(Task fatherTask, Task newTask, String path, Filter chain) {

String prefix = getPrefix(fatherTask.getCurrentPath(), 1);

newTask.init(fatherTask.getHost(), fatherTask.getPort(), prefix + "/" + path);

}

}

public ParseHandler(BlockingQueue<Task> connectlist, BlockingQueue<Task> parselist,

BlockingQueue<Task> persistencelist, List<String> domainlist) {

this.connectlist = connectlist;

this.parselist = parselist;

this.persistencelist = persistencelist;

this.domainlist = domainlist;

}

private Pattern pattern = Pattern.compile("\"[^\"]+\\.htm[^\"]*\"");

private void handler() {

try {

Task task = parselist.take();

parseTaskState(task);

if (200 == task.getState()) {

Matcher matcher = pattern.matcher(task.getContent());

while (matcher.find()) {

String path = matcher.group();

if (!path.contains(" ") && !path.contains("\t") && !path.contains("(") && !path.contains(")")

&& !path.contains(":")) {

path = path.substring(1, path.length() - 1);

if (!SET.contains(path)) {

SET.add(path);

createNewTask(task, path);

}

}

}

}

task.setContent(null);

persistencelist.put(task);

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

private void parseTaskState(Task task) {

if (task.getContent().startsWith("HTTP/1.1")) {

task.setState(Integer.parseInt(task.getContent().substring(9, 12)));

} else {

task.setState(Integer.parseInt(task.getContent().substring(19, 22)));

}

}

/**

* @param fatherTask

* @param path

* @throws Exception

*/

private void createNewTask(Task fatherTask, String path) throws Exception {

Task newTask = new Task();

FilterChain filterchain = new FilterChain();

filterchain.doFilter(fatherTask, newTask, path, filterchain);

if (newTask != null) {

connectlist.put(newTask);

}

}

private String getPrefix(String s, int count) {

String prefix = s;

while (count > 0) {

prefix = prefix.substring(0, prefix.lastIndexOf("/"));

count--;

}

return "".equals(prefix) ? "/" : prefix;

}

@Override

public void run() {

while (true) {

this.handler();

COUNT.addAndGet(1);

}

}

}

class ConnectHandler implements Runnable {

public static int GETCOUNT() {

return COUNT.get();

}

private static final AtomicInteger COUNT = new AtomicInteger();

private BlockingQueue<Task> connectlist;

private BlockingQueue<Task> parselist;

public ConnectHandler(BlockingQueue<Task> connectlist, BlockingQueue<Task> parselist) {

this.connectlist = connectlist;

this.parselist = parselist;

}

private void handler() {

try {

Task task = connectlist.take();

long start = System.currentTimeMillis();

getHtml(task);

long end = System.currentTimeMillis();

task.setTaskTime(end - start);

parselist.put(task);

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

private void getHtml(Task task) throws Exception {

StringBuilder sb = new StringBuilder(2048);

InetAddress addr = InetAddress.getByName(task.getHost());

// 建立一个Socket

Socket socket = new Socket(addr, task.getPort());

// 发送命令,无非就是在Socket发送流的基础上加多一些握手信息,详情请了解HTTP协议

BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));

wr.write("GET " + task.getCurrentPath() + " HTTP/1.0\r\n");

wr.write("HOST:" + task.getHost() + "\r\n");

wr.write("Accept:*/*\r\n");

wr.write("\r\n");

wr.flush();

// 接收Socket返回的结果,并打印出来

BufferedReader rd = new BufferedReader(new InputStreamReader(socket.getInputStream()));

String line;

while ((line = rd.readLine()) != null) {

sb.append(line);

}

wr.close();

rd.close();

task.setContent(sb.toString());

socket.close();

}

@Override

public void run() {

while (true) {

this.handler();

COUNT.addAndGet(1);

}

}

}

class PersistenceHandler implements Runnable {

static {

try {

Class.forName("oracle.jdbc.OracleDriver");

} catch (ClassNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

public static int GETCOUNT() {

return COUNT.get();

}

private static final AtomicInteger COUNT = new AtomicInteger();

private BlockingQueue<Task> persistencelist;

public PersistenceHandler(BlockingQueue<Task> persistencelist) {

this.persistencelist = persistencelist;

try {

conn = DriverManager.getConnection("jdbc:oracle:thin:127.0.0.1:1521:orcl", "edmond", "edmond");

ps = conn

.prepareStatement("insert into probe(id,host,path,state,tasktime,type) values(seq_probe_id.nextval,?,?,?,?,?)");

} catch (SQLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

private Connection conn;

private PreparedStatement ps;

@Override

public void run() {

while (true) {

this.handler();

COUNT.addAndGet(1);

}

}

private void handler() {

try {

Task task = persistencelist.take();

ps.setString(1, task.getHost());

ps.setString(2, task.getCurrentPath());

ps.setInt(3, task.getState());

ps.setLong(4, task.getTaskTime());

ps.setString(5, task.getType());

ps.executeUpdate();

conn.commit();

} catch (InterruptedException e) {

e.printStackTrace();

} catch (SQLException e) {

e.printStackTrace();

}

}

}

  ParseHandler 使用了一个职责链模式,

  TwoLevel 处理../../开头的连接(../../sucai/sucai.htm)

  OneLevel 处理../开头的连接(../sucai/sucai.htm)

  FullPath 处理绝对路径的连接(http://域名/sucai/sucai.htm)

  Root 处理/开头的连接(/sucai/sucai.htm)

  Default 处理常规的连接(sucai.htm)

  ParseHandler FullPath 过滤需要一个白名单.

  这样可以使程序在固定的域名爬行

  ParseHandler parseTaskState 解析状态码 可能需要根据实际情况进行调整

  比如网页404,服务器可能会返回一个错误页,而不是通常的HTTP状态码。

  第一版仅仅实现了功能,错误处理不完整,

  所以仅仅在定制的域名下生效,其实并不通用,后续会逐步完善.

最新内容请见作者的GitHub页:http://qaseven.github.io/

时间: 2024-09-20 00:51:28

网页主动探测工具使用的相关文章

网页抓取工具之数据预处理

提取的数据还不能直接拿来用?文件还没有被下载?格式等都还不符合要求?别着急,网页抓取工具火车采集器自有应对方案--数据处理. 图片1.png 网页抓取工具的数据处理功能包括三个部分,分别是内容处理.文件下载.内容过滤.下面依次给大家介绍: 1.内容处理:对从内容页面提取的数据进行替换.标签过滤.分词等进一步处理,我们可以同时添加多个操作,但这里需要注意的是,有多个操作时是按照从上到下的顺序来执行,也就是说,上个步骤的结果会作为下个步骤的参数. 下面来逐个介绍一下: ①提取内容为空:如果通过前面的

基于JSP网页自动生成工具的设计与实现

js|设计|网页 摘 要:Web开发技术是Internet应用的一个重要方面,而JSP又是Web开发的最先进的技术,是当前Web开发人员的首选技术.但是由于JSP对Web开发人员要求较高,所以许多一般的Web开发人员还不能够使用这一项先进的技术.讨论基于模板和标签库的JSP网页自动生成工具的设计和实现,提出具体的设计思想和实现方法. 关键词:JSP:自动生成:Web开发:标签:标签库:模板 目录: 引言-------------------------..2 1          系统设计目标和

网页设计必备工具和生成器(英文软件)

任何一个行业发展到一个阶段之后,其应用都会越发的平民化,只要你够勤劳,你就可以创造自己的价值,网页设计也同样如此,如今网页设计的辅助软件和在线工具越来越多,并且都细化到了极致,各司其职,为Web设计者更好更快地提高工作效率带来了莫大的帮助,网页教学网为我们翻译整理的28个优秀的快速网页设计必备工具和生成器. 1. Lorem Ipsum Generator 文本排版生成器 2. Stripe Generator 条纹背景 3. Mycoolbutton 按钮生成器 4. Web20generat

js实现带关闭按钮始终显示在网页最底部工具条的方法

 这篇文章主要介绍了js实现带关闭按钮始终显示在网页最底部工具条的方法,是非常实用的javascript固定效果,具有一定参考借鉴价值,需要的朋友可以参考下     本文实例讲述了js实现带关闭按钮始终显示在网页最底部工具条的方法.分享给大家供大家参考.具体如下: 这是一款很实用的代码,给网页加入一个始终显示在浏览器窗口底部的工具栏,可以在上面放上公告,联系人等等信息,此代码的工具条还带有关闭按钮,可以随时关闭   代码如下: <!DOCTYPE html PUBLIC "-//W3C//

网页前端开发工具推荐

  当启动一个新的项目,使用 CSS 框架或样板,可以帮助您节省大量的时间.在这篇文章中,我编译整理了我最喜欢的 CSS样板,框架和库,帮助你在建立网站或应用程序时更加高效. Bootstrap 开发工具推荐-网页前端开发工具"> 如果你想给你的新项目的专业的外观和感觉,Boostrap 可能是你需要的工具.它拥有一个非常干净的排版,表格元素,以及设计一个现代化的网站你需要的所有东西.更多信息: twitter.github.io Foundation Foundation 来自 Zurb

《网页美工设计Photoshop+Flash+Dreamweaver从入门到精通》——1.2 网页美工常用工具

1.2 网页美工常用工具 网页美工设计Photoshop+Flash+Dreamweaver从入门到精通 由于目前所见即所得类型的工具越来越多,使用也越来越方便,所以制作网页已经变成了一件轻松的工作.Dreamweaver.Flash.Photoshop这3个软件相辅相承,是网页美工的首选工具,其中,Dreamweaver主要用来制作网页文件,制作出来的网页兼容性好.制作效率也很高,Flash用来制作精美的网页动画,Photoshop用来处理网页中的图像. 1.2.1 网页编辑排版软件Dream

善用网页抓取工具,数据轻松收入囊中

数据已走进各行各业并得到了广泛应用,伴随着应用而来的则是对数据的获取和准确挖掘.我们可应用的数据多来自内部资源库以及外部载体,内部数据整合即用,而外部数据却需要先行获取.外部数据的最大载体就是互联网,网页中每天难以数计的增量数据里,就包含着许多对我们有利用价值的信息. 如何最高效地从海量信息里获取数据呢?网页抓取工具火车采集器有高招,以自动化的智能工具代替人工的数据收集,当然更高效也更准确. 一.数据抓取的通用性 作为通用的网页抓取工具,火车采集器基于源代码的操作原理让可抓取的网页类型达到99%

objection - 基于 Frida 的 iOS APP Runtime 探测工具

本文讲的是objection - 基于 Frida 的 iOS APP Runtime 探测工具, 介绍 在这篇文章中,我想介绍一下我一直在研究的一个工具包,叫做objection.这个名字其实所隐含的意思就是"object"以及"injection".objection是由Frida提供的可以对移动平台的runtime进行检测的工具包.该工具包目前只在iOS上,其旨在允许您能够在非越狱iOS设备runtime时,在其未加密的iOS应用程序上执行各种安全相关的任务.

《网站设计 开发 维护 推广 从入门到精通》——1.2 网页美工常用工具

1.2 网页美工常用工具 制作网页第一件事就是要选定网页制作软件.虽然用记事本手工编写源代码也能做出网页,但这需要对编程语言相当了解,并不适合于广大的网页设计爱好者.由于目前所见即所得类型的工具越来越多,使用也越来越方便,所以制作网页已经变成了一件轻松的工作. Flash.Dreamweaver和Photoshop这三款软件相辅相成,是制作网页的首选工具,其中Dreamweaver主要用来制作网页文件,利用Dreamweaver制作出来的网页兼容性好,制作效率也很高:Flash用来制作精美的网页