问题
最近公司的市场部分布了一个问题,到一个网站截取一下医院的数据。刚好我也被安排做。后来,我发现为何不用脚本去抓取呢?
抓取的数据如下:
Jsoup的使用实战代码
结构
- java代码
public class GetDoctorInfo {
public GetDoctorInfo() {
ExecutorService threadPool = Executors.newFixedThreadPool(5);
//43有问题
//73有问题
for (int i = 1; i <= 100; i++) {
String path = "http://so.haodf.com/index/search?type=hospitalfaculty&p=" + i + "&kw=%B8%BE%B2%FA%BF%C6";
threadPool.execute(new GetDoctorRun(path));
}
threadPool.shutdown();
}
public static void main(String[] arg) {
new GetDoctorInfo();
}
public static synchronized void printInfo(String sql) {
System.out.println(sql);
}
public static String trans(String input) {
String value;
value = input.replaceAll("<td>", "").replaceAll("</td>", "").replaceAll(" ", "").replaceAll(" 地址地图:", "");
return value;
}
/**
* 获取医生的线程
*/
public class GetDoctorRun implements Runnable {
final String mURL;
public GetDoctorRun(String mURL) {
this.mURL = mURL;
}
@Override
public void run() {
try {
Document doc = null;
try {
// doc = (Document) Jsoup.parse(new URL("http://so.haodf.com/index/search?type=hospitalfaculty&p=99&kw=%B8%BE%B2%FA%BF%C6")
// , 1000);
doc = (Document) Jsoup.parse(new URL(mURL), 3000);
} catch (IOException e) {
e.printStackTrace();
}
//定位到列表
Elements elements = doc.getElementsByClass("list");
Elements childElements = elements.get(0).getAllElements();
Element child = childElements.get(3);
//获得所有的超链接的数据
Elements aLinks = child.getElementsByTag("a");
ArrayList<String> name = new ArrayList<>();
ArrayList<String> address = new ArrayList<>();
for (int i = 1; i <= aLinks.size(); i++) {
Element e = aLinks.get(i - 1);
if (e.attr("target").equals("_blank")) {
//排除 科室介绍
//排除 门诊时间
if (!e.text().equals("科室介绍") && !e.text().equals("门诊时间")) {
// System.out.println("--" + e.text());
if (i % 2 == 0) {
if (e.text().equals("") || e.text() == null) {
address.add("");
} else {
address.add(e.text());
}
} else {
if (e.text().equals("") || e.text() == null) {
name.add("");
} else {
name.add(e.text());
}
}
}
}
}
//将长连接的内容删除
child.select("a").remove();
child.select("span").remove();
child.select("br").remove();
String tran = trans(child.toString());
// System.out.println(tran);
String[] phones = tran.substring(" 电 话:".length(), tran.length() - 1).split("电 话:");
System.out.println();
System.out.println();
System.out.println();
for (int i = 0; i < name.size(); i++) {
// System.out.println(phones[i]);
// //INSERT INTO info(hospital_name,address,phone) VALUES ('gg','hhh','ddd');
StringBuffer bufferValue = new StringBuffer("INSERT INTO info(hospital_name,address,phone) VALUES (");
//医院名
bufferValue.append("'").append(name.get(i)).append("'");
//医院地址
bufferValue.append(",'").append(address.get(i)).append("'");
//医院的电话
bufferValue.append(",'").append(phones[i].trim()).append("');");
printInfo(bufferValue.toString());
}
if (name.size() != 10) {
System.out.println("name==" + mURL);
}
if (address.size() != 10) {
System.out.println("address=" + mURL);
}
if (phones.length != 10) {
System.out.println("phone=" + phones.length + " " + mURL);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
- Terminal写入sqlte
.open hospital.db
sqlite3 -init sql
总结
jsoup的使用很简单,有点像解析xml。不过结果很好的,因为5,6个人的工作就被这个简单的代码实现了。解析技巧有一个尽量清除不必要的标签。如代码:
child.select("a").remove();
child.select("span").remove();
child.select("br").remove();
- 学会用脚本收集数据
- 注意多谢线程并发的安全,要检验,要不很易出错
- 对于多线程的问题关键是要确保你的内容不被竞争弄乱,所以提取出来进行代码块是很重要的。
最后补充一下最终的效果如下图