Предыдущий:Практика веб-краулера Java (2)
Эта статья в основном знакомитNetDiscoveryНекоторые практические применения конвейерного режима в фреймворке.
1) Что такое трубопровод
Конвейер — это распространенный шаблон алгоритма.Для трудоемких задач, которые непрерывно зацикливаются, если пришло время дождаться окончания цикла для обработки следующей задачи, это пустая трата времени.
Поэтому трудоемкая задача разбивается на несколько звеньев, пока одно звено выполнено, сразу может быть обработано звено следующего задания. Не ждите, пока эта трудоемкая задача будет завершена, прежде чем начинать.
Я думаю, что приложение очень подходит для обработки данных, полученных краулером.
2) Роль пайплайна в фреймворке
Из схемы, предоставленной фреймворком, мы можем понять, какова роль объекта конвейера:
- URL-адрес доступа к объекту загрузчика
- После успешного доступа объект страницы передается объекту анализатора для анализа страницы.
- Отдайте результаты парсинга объекту конвейера для обработки по одному, например: дедупликация, инкапсуляция, хранение, отправка сообщений и т. д.
3) целевая задача
Шаги задачи:
- Посетите веб-сайт Pull Hook
- Поиск ссылок на изображения на веб-страницах
- Скачать картинку по ссылке на локальный
- Сохранить информацию об изображении в базу данных mysql
4) Создайте объект конвейера
класс конвейера: DownloadImage
package com.sinkinka.pipeline;
import com.cv4j.netdiscovery.core.domain.ResultItems;
import com.cv4j.netdiscovery.core.pipeline.Pipeline;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Map;
public class DownloadImage implements Pipeline {
@Override
public void process(ResultItems resultItems) {
Map<String, Object> map = resultItems.getAll();
for(String key : map.keySet()) {
String filePath = "./temp/" + key + ".png";
saveRemoteImage(map.get(key).toString(), filePath);
}
}
private boolean saveRemoteImage(String imgUrl, String filePath) {
InputStream in = null;
OutputStream out = null;
try {
URL url = new URL(imgUrl);
URLConnection connection = url.openConnection();
connection.setConnectTimeout(5000);
in = connection.getInputStream();
byte[] bs = new byte[1024];
int len;
out = new FileOutputStream(filePath);
while ((len = in.read(bs)) != -1) {
out.write(bs, 0, len);
}
} catch(Exception e) {
return false;
} finally {
try {
out.flush();
out.close();
in.close();
} catch(IOException e) {
return false;
}
}
return true;
}
}
класс конвейера: SaveImage
package com.sinkinka.pipeline;
import com.cv4j.netdiscovery.core.domain.ResultItems;
import com.cv4j.netdiscovery.core.pipeline.Pipeline;
import com.safframework.tony.common.utils.Preconditions;
import java.sql.*;
import java.util.Map;
public class SaveImage implements Pipeline {
@Override
public void process(ResultItems resultItems) {
Map<String, Object> map = resultItems.getAll();
for(String key : map.keySet()) {
System.out.println("2"+key);
saveCompanyInfo(key, map.get(key).toString());
}
}
private boolean saveCompanyInfo(String shortName, String logoUrl) {
int insertCount = 0;
Connection conn = getMySqlConnection();
Statement statement = null;
if(Preconditions.isNotBlank(conn)) {
try {
statement = conn.createStatement();
String insertSQL = "INSERT INTO company(shortname, logourl) VALUES('"+shortName+"', '"+logoUrl+"')";
insertCount = statement.executeUpdate(insertSQL);
statement.close();
conn.close();
} catch(SQLException e) {
return false;
} finally {
try{
if(statement!=null) statement.close();
}catch(SQLException e){
}
try{
if(conn!=null) conn.close();
}catch(SQLException e){
}
}
}
return insertCount > 0;
}
//演示代码,不建议用于生产环境
private Connection getMySqlConnection() {
//使用的是mysql connector 5
//数据库:test 账号/密码: root/123456
final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
final String DB_URL = "jdbc:mysql://localhost:3306/test";
final String USER = "root";
final String PASS = "123456";
Connection conn = null;
try {
Class.forName(JDBC_DRIVER);
conn = DriverManager.getConnection(DB_URL,USER,PASS);
} catch(SQLException e) {
return null;
} catch(Exception e) {
return null;
}
return conn;
}
}
5) Запускаем программу
Основной класс
package com.sinkinka;
import com.cv4j.netdiscovery.core.Spider;
import com.sinkinka.parser.LagouParser;
import com.sinkinka.pipeline.DownloadImage;
import com.sinkinka.pipeline.SaveImage;
public class PipelineSpider {
public static void main(String[] args) {
String url = "https://xiaoyuan.lagou.com/";
Spider.create()
.name("lagou")
.url(url)
.parser(new LagouParser())
.pipeline(new DownloadImage()) //1. 首先,下载图片到本地目录
.pipeline(new SaveImage()) //2. 然后,把图片信息存储到数据库
.run();
}
}
Класс парсера
package com.sinkinka.parser;
import com.cv4j.netdiscovery.core.domain.Page;
import com.cv4j.netdiscovery.core.domain.ResultItems;
import com.cv4j.netdiscovery.core.parser.Parser;
import com.cv4j.netdiscovery.core.parser.selector.Selectable;
import java.util.List;
public class LagouParser implements Parser {
@Override
public void process(Page page) {
ResultItems resultItems = page.getResultItems();
List<Selectable> liList = page.getHtml().xpath("//li[@class='nav-logo']").nodes();
for(Selectable li : liList) {
String logoUrl = li.xpath("//img/@src").get();
String companyShortName = li.xpath("//div[@class='company-short-name']/text()").get();
resultItems.put(companyShortName, logoUrl);
}
}
}
Через DownloadImage сохраните данные изображения в локальную папку:
Через SaveImage данные сохраняются в базе данных:
6) Резюме
Приведенный выше код просто демонстрирует использование режима конвейера.Помните, что у конвейера есть порядок выполнения. Давайте испытаем преимущества конвейерного режима в производственной среде с большим объемом данных и высокой частотой.
Следующий:Практика веб-краулера Java (4)