一、
网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。另外一些不常使用的名字还有蚂蚁、自动索引、模拟程序或者蠕虫
二、
采集步骤:
1:分析采集内容
2:发送Http请求
- 解析请求返回元素
- 存储采集内容
- 分析采集内容
Demo:采集肖申克的救赎的影评 (标题、评论)
https://movie.douban.com/subject/1292052/reviews?start=20
分析请求地址
https://movie.douban.com/subject/1292052/reviews?start=20
响应方式:text/html
2.发送http请求(get/post)下面的表格比较了两种 HTTP 方法:GET 和 POST。
|
|
GET |
POST |
|
后退按钮/刷新 |
无害 |
数据会被重新提交(浏览器应该告知用户数据会被重新提交)。 |
|
书签 |
可收藏为书签 |
不可收藏为书签 |
|
缓存 |
能被缓存 |
不能缓存 |
|
编码类型 |
application/x-www-form-urlencoded |
application/x-www-form-urlencoded 或 multipart/form-data。为二进制数据使用多重编码。 |
|
历史 |
参数保留在浏览器历史中。 |
参数不会保存在浏览器历史中。 |
|
对数据长度的限制 |
是的。当发送数据时,GET 方法向 URL 添加数据;URL 的长度是受限制的(URL 的最大长度是 2048 个字符)。 |
无限制。 |
|
对数据类型的限制 |
只允许 ASCII 字符。 |
没有限制。也允许二进制数据。 |
|
安全性 |
与 POST 相比,GET 的安全性较差,因为所发送的数据是 URL 的一部分。 在发送密码或其他敏感信息时绝不要使用 GET ! |
POST 比 GET 更安全,因为参数不会被保存在浏览器历史或 web 服务器日志中。 |
|
可见性 |
数据在 URL 中对所有人都是可见的。 |
数据不会显示在 URL 中。 |
Apache HttpClient
HttpClient是Apache Jakarta Common下的子项目,用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支持HTTP协议最新的版本和建议。HttpClient已经应用在很多的项目中,比如Apache Jakarta上很著名的另外两个开源项目Cactus和HTMLUnit都使用了HttpClient。
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.4</version>
</dependency>
向豆瓣评论发送请求
private String httpGet(String url) {
String result = "";
try {
result = EntityUtils.toString(new DefaultHttpClient()
.execute(new HttpGet(url)).getEntity(),
"utf-8");
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
3.解析采集内容
Jsoup是用于解析HTML,就类似XML解析器用于解析XML。 Jsoup它解析HTML成为真实世界的HTML。 它与jquery选择器的语法非常相似,并且非常灵活容易使用以获得所需的结果
选择器例子:
Elements links = doc.select("a[href]"); //带有href属性的a元素
Elements pngs = doc.select("img[src$=.png]"); //扩展名为.png的图片
Element masthead = doc.select("div.masthead").first();//class等于masthead的div标签
Elements resultLinks = doc.select("h3.r > a"); //在h3元素之后的a元素
解析豆瓣评论返回采集内容
Html doubanMoveComment = page.getHtml();
Document doubanMoveDocument = doubanMoveComment.getDocument();
Elements headerElements = doubanMoveDocument.select("div.main-bd");
headerElements.forEach(elements -> {
String title = elements.select("h2").text();
String comment = elements.select("div.short-content").text();
log.info("title:" + title + " comment:" + comment);
});
4.完整例子
public static void main(String args[]) throws Exception {
String target = "https://movie.douban.com/subject/1292052/reviews?start=20";
DoubanSpider1 spider = new DoubanSpider1();
spider.process(target);
}
public void process(String target) throws Exception {
String httpgetRes = httpGet(target);
Html doubanMoveComment = new Html(httpgetRes);
Document doubanMoveDocument = doubanMoveComment.getDocument();
Elements headerElements = doubanMoveDocument.select("div.main-bd");
headerElements.forEach(elements -> {
String title = elements.select("h2").text();
String comment = elements.select("div.short-content").text();
System.out.println("title:" + title + " comment:" + comment);
});
}
private String httpGet(String url) {
String result = "";
try {
result = EntityUtils.toString(new DefaultHttpClient()
.execute(new HttpGet(url)).getEntity(),
"utf-8");
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
三、存在的问题
1、采集效率低
2、如果采集数据量大,单机难以实现
3、针对每个不同的地址需要写一套采集程序、无法统一管理运行
- 解决方案
解决方案:
1、单线程改成多线程
String target = "https://movie.douban.com/subject/1292052/reviews?start=";
DoubanSpider2 spider = new DoubanSpider2();
ExecutorService executorService = Executors.newFixedThreadPool(threadSize);
CountDownLatch latch = new CountDownLatch(threadSize);
for (int index = 0; index < threadSize; index++) {
int i = index;
Runnable task = () -> {
String address = target + i * 20 + 20;
spider.process(address);
latch.countDown();
};
executorService.submit(task);
}
latch.await();
- 采用webmagic集成框架(集成多线程+Http)
webmagic是一个开源的Java垂直爬虫框架,目标是简化爬虫的开发流程,让开发者专注于逻辑功能的开发
<dependency>
<groupId>us.codecraft</groupId> <artifactId>webmagic-core</artifactId>
<version>0.5.3</version>
</dependency>
<dependency>
<groupId>us.codecraft</groupId>
<artifactId>webmagic-extension</artifactId>
<version>0.5.3</version>
</dependency>
/*设置抓取网站的相关配置*/
private Site site = Site.me().setRetryTimes(3).setSleepTime(100);
/*爬取*/
public static void main(String args[]) {
String target = "https://movie.douban.com/subject/1292052/reviews?start=20";
Spider.create(
new DoubanSpider3())
.addUrl(target)
.thread(5)
.run();
}
/*爬取逻辑*/
public void process(Page page) {
Html doubanMoveComment = page.getHtml();
Document doubanMoveDocument = doubanMoveComment.getDocument();
Elements headerElements = doubanMoveDocument.select("div.main-bd");
headerElements.forEach(elements -> {
String title = elements.select("h2").text();
String comment = elements.select("div.short-content").text();
System.out.println("title:" + title + " comment:" + comment);
});
}
- 动态执行采集任务
private final static String targetPath = "D:/luowang/luowang_spider/out/artifacts/DoubanSpider3/DoubanSpider3.jar";
public static void main(String args[]) {
URL[] urls = new URL[]{};
DoubanClassLoader classLoader = new DoubanClassLoader(urls);
try {
classLoader.addJar(new File(targetPath).toURI().toURL());
Class<?> clazz = classLoader.loadClass("com.css.website.douban.DoubanSpider3");
DoubanSpider3 spider3 = (DoubanSpider3)clazz.newInstance();
spider3.runSpider();
classLoader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
static class DoubanClassLoader extends URLClassLoader {
DoubanClassLoader(URL[] urls) {
super(urls);
}
public DoubanClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
}
void addJar(URL url) {
this.addURL(url);
}
}
- 采用分布式调度任务+动态加载采集程序+Webmagic(分布式爬虫系统)
- 通过webmagic编写采集程序
- 将需要采集地址、编写的采集程序打成jar上传到系统管理中心(可用redis/ftp)存储
- 系统接到任务后分片执行采集任务