php多线程抓取多个网页(用Java+Jsoup实现简单的网页爬虫功能,你知道吗?)

优采云 发布时间: 2022-03-16 01:16

  php多线程抓取多个网页(用Java+Jsoup实现简单的网页爬虫功能,你知道吗?)

  上一篇介绍了使用Java+Jsoup实现一个简单的网络爬虫功能。这次我们再深入一点,同时抓取多个新闻网站,并将有用的信息(新闻标题、URL、新闻内容等)存储在数据库中。先介绍一个非常好用的多线程爬虫框架AiPa。

  AiPa爬虫框架

  Aipa 是一个小型、灵活且高度可扩展的多线程爬虫框架。

  AiPa 依赖于 Jsoup,这是目前最简单的 HTML 解析器。

  AiPa只需要用户提供一个URL集合,它就可以在多线程下自动爬取并处理一些异常。

  马文

  直接*敏*感*词*

  

cn.yueshutong

AiPa

1.0.0.RELEASE

  采用

  1.必须实现的接口:

  public class MyAiPaWorker implements AiPaWorker {

@Override

public String run(Document doc, AiPaUtil util) {

//使用JSOUP进行HTML解析获取想要的div节点和属性

//保存在数据库或本地文件中

//新增aiPaUtil工具类可以再次请求网址

return doc.title() + doc.body().text();

}

@Override

public Boolean fail(String link) {

//任务执行失败

//可以记录失败网址

//记录日志

return false;

}

}

  2.主要方法

   public static void main(String[] args) throws InstantiationException, IllegalAccessException, ExecutionException, InterruptedException {

//准备网址集合

List linkList = new ArrayList();

linkList.add("http://jb39.com/jibing/FeiQiZhong265988.htm");

linkList.add("http://jb39.com/jibing/XiaoErGuoDu262953.htm");

linkList.add("http://jb39.com/jibing/XinShengErShiFei250995.htm");

linkList.add("http://jb39.com/jibing/GaoYuanFeiShuiZhong260310.htm");

linkList.add("http://jb39.com/zhengzhuang/LuoYin337449.htm");

//第一步:新建AiPa实例

AiPaExecutor aiPaExecutor = AiPa.newInstance(new MyAiPaWorker()).setCharset(Charset.forName("GBK"));

//第二步:提交任务

for (int i = 0; i < 10; i++) {

aiPaExecutor.submit(linkList);

}

//第三步:读取返回值

List futureList = aiPaExecutor.getFutureList();

for (int i = 0; i < futureList.size(); i++) {

//get() 方法会阻塞当前线程直到获取返回值

System.out.println(futureList.get(i).get());

}

//第四步:关闭线程池

aiPaExecutor.shutdown();

}

  3. AiPaWorker 接口

  AiPaWorker 接口是用户必须实现的业务类。

  该接口的方法如下:

  public interface AiPaWorker {

/**

* 如何解析爬下来的HTML文档?

* @param doc JSOUP提供的文档

* @param util 爬虫工具类

* @return

*/

T run(Document doc, AiPaUtil util);

/**

* run方法异常则执行fail方法

* @param link 网址

* @return

*/

S fail(String link);

}

  注意接口中run方法的参数doc,也就是Jsoup通过连接网页URL得到的文档,可以直接使用。

  在run方法中,可以通过Jsoup方法爬取想要的数据,然后存入数据库。请注意,它是在 run 方法中执行的。

  数据库访问操作。

  即run()方法是用户自定义处理抓取到的HTML内容,一般使用Jsoup的Document类来解析。

  获取节点或属性等并保存到数据库或本地文件。如果需要在业务方法中再次请求 URL,可以使用

  工具类 Util。例如,在访问特定新闻页面时。

  fail()方法是run方法发生异常或者爬取网页时进入的方法,多次处理无效。该方法的参数

  是这次出错的网址。一般用于日志等操作。

  以上是对AiPa框架的基本介绍。让我们从一个在多个新闻网站 上爬取新闻的简单示例开始。

  网页的配置信息存储在数据库中。第一步是从数据库中获取要爬取的网站的各种配置信息。

   //取数据库内配置列表

List articleCrawler= this.articleCrawlerDomain.getAllArticle();

List linkList = new ArrayList();

for (int i = 0; i < articleCrawler.size(); i++) {

String url = articleCrawler.get(i).getUrl();//获取网页Url

String ulClass = articleCrawler.get(i).getUlClass();//获取ul标签样式

String articleName = articleCrawler.get(i).getTname();//获取网页新闻名称

String contentClass = articleCrawler.get(i).getContentClass();//获取网页内容样式

String authorClass = articleCrawler.get(i).getAuthorClass();//获取新闻作者样式

String webCode = articleCrawler.get(i).getWebCode();//获取网页编码格式

String tableClass = articleCrawler.get(i).getTableClass();//获取表格样式

String listClass = articleCrawler.get(i).getListClass();//获取li标签样式

String divClass = articleCrawler.get(i).getDivClass();//获取div标签样式

String websiteUrl = articleCrawler.get(i).getWebsiteUrl();//获取网站官网URL

linkList.add(url);//设置网址集合

  获取配置信息后,新建一个AiPa框架,在run方法中使用Jsoup的Document类解析,获取节点和属性,然后

  调用方法存储在本地数据库中。

<p>//新建AiPa框架类

AiPaExecutor executor = AiPa.newInstance(new AiPaWorker(){

@Override

public Boolean run(Document document, AiPaUtil util) {

List contentList = new ArrayList();

List articleList = new ArrayList();

//如果新闻格式为无序列表且ul上有样式,格式为

if(ulClass!=null){

Elements ulLinks = document.getElementsByClass(ulClass);//根据ul的样式获取ul

for (Element ulLink : ulLinks) {

Elements liLinks = ulLink.getElementsByTag("li");//获取ul下的li

for (Element liLink : liLinks){

Elements aLinks = liLink.select("a");//获取li下的a标签

for (Element aLink : aLinks){

String title = aLink.text();//获取新闻标题

String titleUrl = aLink.attr("href");//获取新闻链接

List articleExist = articleDomain.queryByProperty("inforsource", titleUrl);

try {

if(title.length()>4 && titleUrl != "javascript:void(0);" && (articleExist == null || articleExist.size()== 0)){

Article article = (Article) articleDomain.getBaseObject();

article.setTname(title);

article.setInforsource(titleUrl);

article.setValid(false);

article.setColumnName(articleName);

article.setCreateId("admin");

contentList.add(titleUrl);

articleList.add(article);

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

}

articleDomain.deleteAndSaveAndUpdate(null, articleList, null);

}

//如果新闻格式为无序列表且ul上有样式,格式为

if (ulClass == null && listClass !=null ) {

Elements listEle = document.getElementsByClass(listClass);

for(Element list : listEle){

Elements ulEle = list.getElementsByTag("ul");

for(Element ulLink :ulEle){

Elements liLinks = ulLink.getElementsByTag("li");//获取ul下的li

for (Element liLink : liLinks){

Elements aLinks = liLink.select("a");//获取li下的a标签

for (Element aLink : aLinks){

String title = aLink.text();//获取新闻标题

String titleUrl = aLink.attr("href");//获取新闻链接

List articleExist = articleDomain.queryByProperty("inforsource", titleUrl);

try {

if(title.length()>4 && titleUrl != "javascript:void(0);" && (articleExist == null || articleExist.size()== 0)){

Article article = (Article) articleDomain.getBaseObject();

article.setTname(title);

article.setInforsource(titleUrl);

article.setValid(false);

article.setColumnName(articleName);

article.setCreateId("admin");

contentList.add(titleUrl);

articleList.add(article);

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

}

}

articleDomain.deleteAndSaveAndUpdate(null, articleList, null);

}

//如果新闻格式没有列表,为<a></a>

if(ulClass == null && divClass != null){

Elements divEle = document.getElementsByClass(divClass);

for(Element div : divEle){

Elements aEle = div.select("a");//取div下的a标签

for(Element aLink : aEle){

String title = aLink.text();//获取新闻标题

String titleUrl = aLink.attr("href");//获取新闻链接

List articleExist = articleDomain.queryByProperty("inforsource", titleUrl);

try {

if(title.length()>4 && titleUrl != "javascript:void(0);" && (articleExist == null || articleExist.size()== 0)){

Article article = (Article) articleDomain.getBaseObject();

article.setTname(title);

article.setInforsource(titleUrl);

article.setValid(false);

article.setColumnName(articleName);

article.setCreateId("admin");

contentList.add(titleUrl);

articleList.add(article);

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

articleDomain.deleteAndSaveAndUpdate(null, articleList, null);

}

//获取新闻详细内容信息

for (int j = 0; j < contentList.size(); j++) {

String articleUrl = (String) contentList.get(j);//获取新闻详细内容链接

//验证新闻URL是否有效

Boolean testUrl = testUrl(articleUrl, 2000);

if(testUrl == false){

String substring = articleUrl.substring(0, 1);

if(".".equals(substring)){

articleUrl = articleUrl.replace("./", url);

}else{

articleUrl = websiteUrl + articleUrl;

}

}

try {

Document contentDoc = util.getHtmlDocument(articleUrl);//根据链接获取详细页面Document

Elements contentEle = contentDoc.getElementsByClass(contentClass);

String author = "";

if(authorClass!=null){

Elements authorEle = contentDoc.getElementsByClass(authorClass);

author = authorEle.text();//获取作者信息

}

String contentHtml = contentEle.html();//获取详细内容的HTML

String content = Jsoup.clean(contentHtml, Whitelist.basicWithImages());//Jsoup对网页HTML进行过滤,筛选标签内容

List articleExist = articleDomain.queryByProperty("inforsource", (String) contentList.get(j));

for (int k = 0; k < articleExist.size(); k++) {

Article article = (Article) articleExist.get(k);

String id = article.getId();

String clobInfo = clobInfoDomain.query(id);

if (!contentHtml.equals("") && (clobInfo == null || clobInfo.length()

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线