记得是这个月9号来深圳的,找了快20天的工作,结果只有那么三四家公司打电话要我去面试,真的不知道什么原因啊。是我投简历投简历投少了么?还是这个季节就是招聘冷季节?真的不清楚。前天去一家创业公司面试,公司感觉还好,整体还算满意,很幸运的被面试上了。谈的工资也是我能接受的,就答应了去上班。今天是第一天去上班,晚上回到住处就在思索着写点什么东西来呢?这个月就要结束了。时间真的过得很快,不过还好,在找工作过程中,自己看了一些书,写了两个小程序。就把前两天在弄得用java抓取网页数据的程序记录下来。以供后面参考。
一般抓取网页数据都是用PHP,Python,Ruby等脚本语言,其实像Java,C++也是可以的,只是可能操作的时候没那么方便。抓取网页原理都一样,通过正则表达式把所关注的网页数据从网页里面提取出来,然后在进行操作(写入文件或者数据库等)。java中操作正则表达式主要用到java.util.regex这个包。比如我们要把某个网页中的<title>XXX</title>中的XXX提取出来,这个时候怎么做呢?
/**
* 获取网页title
*
* @param pageStr
* @return
*/
public static String getPageTitle(String pageStr) {
String titleRegStr = "<title>(.*)</title>";
Pattern pattern = Pattern
.compile(titleRegStr, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(pageStr);
String pageTitle = "";
if (matcher.find(0)) {
pageTitle = matcher.group(1);
}
return pageTitle;
}
通过上面代码就可提取出来,注意传入参数是整个要提取的网页字符串。返回的就是网页title。
网页中图片链接一般都是这样写的: <img src="XXX" onClicked="XXX" /> 一般网页的连接都是类似这样<a href="XXX" target="_blank"/>。抓取src后面的值和href后面的值原理是一样的。
/**
* 得到网页中图片的地址
*/
public static List<String> getImgStr(String htmlStr, String url) {
StringBuffer imgBuffer = new StringBuffer();
Pattern p_image;
Matcher m_image;
List<String> pics = new ArrayList<String>();
String cache_file_name = url.substring(url.lastIndexOf("/") +1);
File file = new File(CACHE_PATH+"/"+cache_file_name);
if (file.exists()) {
try {
FileInputStream fis = new FileInputStream(file);
int length = 0;
byte[] buffer = new byte[1024*100];
while ((length = fis.read(buffer))!= -1){
imgBuffer.append(new String(buffer, 0, length));
}
fis.close();
Matcher m = Pattern.compile("src=\"?(.*?)(\"|>|\\s+)").matcher(imgBuffer.toString()); // 匹配src
while (m.find()) {
pics.add(m.group(1));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}else{
String regEx_img = "<img.*src=(.*?)[^>]*?>"; // 图片链接地址
p_image = Pattern.compile(regEx_img, Pattern.CASE_INSENSITIVE);
m_image = p_image.matcher(htmlStr);
while (m_image.find()) {
imgBuffer.append(",").append(m_image.group());
Matcher m = Pattern.compile("src=\"?(.*?)(\"|>|\\s+)").matcher(imgBuffer.toString()); // 匹配src
while (m.find()) {
pics.add(m.group(1));
}
}
if (pics.size()>0) {
File cacheFile = new File(CACHE_PATH + "/" + cache_file_name);
try {
FileOutputStream fos = new FileOutputStream(cacheFile);
fos.write(imgBuffer.toString().getBytes());
fos.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
return pics;
}
这里我会将单个网页已经做了正则匹配后的所有值连接在一起存入缓存文件中。省的再次抓取相同的网页时又去做正则匹配,耗时。注意两个地方:一个是图片链接地址,还有一个是匹配src。我们先找出链接的全地址如<img src="XXX" /> ,然后在做一次正则匹配找到src的值。最后返回单个网页的所有图片的链接地址。知道链接地址,接下来你就可以下载图片了。抓取网页的<a href="XXX" />链接也类似。至于获取网页代码只要去读取该网页到字符串中即可:
/**
* 获取网页源码
*
* @param pageUrl
* @param encoding
* @return
*/
public static String getPageSource(String pageUrl, String encoding) {
StringBuffer sb = new StringBuffer();
try {
URL url = new URL(pageUrl);
BufferedReader in = new BufferedReader(new InputStreamReader(
url.openStream(), encoding));
String line;
while ((line = in.readLine()) != null) {
sb.append(line);
sb.append("\n");
}
in.close();
} catch (Exception e) {
System.err.println(e);
}
return sb.toString();
}
要注意这里有个网页编码参数,根据该网页的编码传入对应的参数,否则可能会出现乱码情况。网页抓取说到底就是正则表达式的强悍体现,最近也有再看一些。就写到这,欢迎大家一起交流。