java爬虫中IO流可以节省时间,使用IO流可以加快编写数据解析逻辑的速度,爬取到的数据在何时入库,在程序出现异常而中断时如何保护数据,程序在异常后继续执行需要怎么做,讲一讲java爬虫中会遇到的问题
当初我写的第一个实战爬虫只是做到登录后把网页源码全部保存下来的功能,就是使用IO流将源码保存到本地
当时很傻很天真,随后就意识到源码的数量有些庞大
但随着不断完善并使用新的技术来爬取数据后,逐渐意识到IO的价值也很大
JavaIO流,是一种计算机用语。主要是用于处理数据的传输。
1.按流的方向分为:输入流和输出流
2.按流的数据单位不同分为:字节流和字符流
3.按流的功能不同分为:节点流和处理流
-------来自百度百科(不想解释太多,直接干货)
对于我来说IO流大多是时间用来将数据本地化操作,以及测试数据筛选时读取本地H5源码的作用.
一句话就是:
在没有写数据筛选时先将目标网页保存到本地,在测试筛选语句时调用本地数据,减少由于测试筛选语句而频繁访问目标网站,减少双方的不便,当然只是保存一两个页面源码即可,当测试完筛选语句后即可将数据源转为实时页面
在我过去写过的一个工具类爬虫里有几个模块
1.爬取:爬取方法分为爬取动态静态
2.网络:ip池:本地ip,高匿ip
3.模拟浏览器:user_agent池
4.IO流读写:保存本地,读取本地
5.数据筛选:测试使用
因为是工具,用于对目标网站进行测试使用
步骤大致就是
1.爬取目标数据
2.使用IO保存到本地
3.按照保存好的本地数据写筛选方法
4.根据数据设计数据库
5.当一切都测试完将代码上传至服务器
结束
贴一下我的IO流方法吧,比较简单比较实用
/**
* IO数据保存本地
* @param H5data 将要保存本地的数据
* @param filename 文件名称
*/
public void input(String H5data, String filename) {
FileOutputStream fos = null;
OutputStreamWriter osw = null;
try {
String address = "ABCDEFG:\"" + filename + ".txt";
fos = new FileOutputStream(address);
osw = new OutputStreamWriter(fos, "gb2312");
osw.write(H5data);
osw.close();
System.out.println("保存完毕");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
if (osw != null) {
try {
osw.close();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
/**
* 读取本地数据
* @param address 文件地址
* @return
*/
public String output(String address) {
String txt1 = "";
String txt2 = "";
String no = "1";
File file = new File(address);
BufferedReader br = null;
FileInputStream fis;
if (file.isFile()) {
try {
fis = new FileInputStream(address);
br = new BufferedReader(new InputStreamReader(fis, "gb2312"));
while ((no = br.readLine()) != null) {
txt1 = no;
txt2 = txt2.concat(txt1.trim());
}
} catch (FileNotFoundException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
} else {
System.out.println("文件不存在");
}
return txt2;
}
数据库想必大家使用的都很熟练
但最近在对国外数据进行获取时由于网络问题,导致了在数据获取时中断,由于数据是在全部获取完进行入库操作,导致一个报错,程序中断,事后反思了一下,有一下多个因素导致
1.网络问题
2.逻辑上没有对易报异常位进行处理
3.数据入库在全部数据获取后执行,程序一旦异常执行中止
之后做的处理有以下几处
1.对常报错位加入判断处理
2.对爬取方法使用try catch finally,异常抛出并对异常数据写入日志,写入异常表,将异常逻辑
加入消息队列在其他时间再次执行,并继续执行之后逻辑
3. a.对需要入库的数据每当解析一条后直接入库(但需要频繁访问数据库,不推荐)
b.使用redis缓存,每当解析一条后保存到缓存中,逻辑执行完,在对缓存中存储的数据进行入库操作(推荐)
c.使用try catch finally 数据在异常时不完整时也返回给入库方法,与第二条思路一致,只是实现起来比较麻烦
4.消息队列:将出现异常时将异常执行的数据换个时间重新执行一遍,再进行入库(用于爬取链接由于网络问题中断而重新执行)