zoukankan      html  css  js  c++  java
  • WebCollector爬取百度搜索引擎样例

    使用WebCollector来爬取百度搜索引擎依照关键字搜索的结果页面,解析规则可能会随百度搜索的改版而失效。

    代码例如以下:

    package com.wjd.baidukey.crawler;
    
    import java.io.ByteArrayInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.net.URLEncoder;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.TimeZone;
    
    import org.apache.poi.poifs.filesystem.DirectoryEntry;
    import org.apache.poi.poifs.filesystem.POIFSFileSystem;
    import org.jsoup.nodes.Element;
    import org.jsoup.select.Elements;
    
    import cn.edu.hfut.dmic.contentextractor.ContentExtractor;
    import cn.edu.hfut.dmic.webcollector.model.CrawlDatum;
    import cn.edu.hfut.dmic.webcollector.model.CrawlDatums;
    import cn.edu.hfut.dmic.webcollector.model.Page;
    import cn.edu.hfut.dmic.webcollector.plugin.ram.RamCrawler;
    
    public class BdiduKeywordCrawler extends RamCrawler{
    
    	private Connection connection;  
    	private PreparedStatement pstatement; 
    	// 连接MySql数据库。用户名root,密码mahao
    	String url = "jdbc:mysql://localhost:3306/wjd";
    	String username = "root";
    	String password = "mahao";
    	//保存抽取到的数据
    	StringBuilder result = new StringBuilder();
    	public BdiduKeywordCrawler(String keyword, int maxPageNum) throws Exception {
    		for (int pageNum = 1; pageNum <= maxPageNum; pageNum++) {
    			String url = createUrl(keyword, pageNum);
    			CrawlDatum datum = new CrawlDatum(url)
    					.putMetaData("keyword", keyword)
    					.putMetaData("pageNum", pageNum + "")
    					.putMetaData("pageType", "searchEngine")
    					.putMetaData("depth", "1");
    			addSeed(datum);
    		}
    	}
    	@Override
    	public void visit(Page page, CrawlDatums next) {
    		String keyword = page.getMetaData("keyword");
    		String pageType = page.getMetaData("pageType");
    		int depth = Integer.valueOf(page.getMetaData("depth"));
    		if (pageType.equals("searchEngine")) {
    			int pageNum = Integer.valueOf(page.getMetaData("pageNum"));
    			System.out.println("成功抓取关键词" + keyword + "的第" + pageNum + "页搜索结果");
    			// || div[class=result-op c-container xpath-log ]>h3>a
    			Elements results = page.select("div[class=result c-container ]>h3>a");
    		//	Elements results1 = page.select("div[class=result-op c-container xpath-log]>h3>a");//,div[id=result-op c-container xpath-log]>h3>a
    			//System.out.println(results1.get(0));
    			//results.add(results1.get(0));
    			for (int rank = 0; rank < results.size(); rank++) {
    				Element result = results.get(rank);
    				/*
    				 * 我们希望继续爬取每条搜索结果指向的网页,这里统称为外链。

    * 我们希望在訪问外链时仍然能够知道外链处于搜索引擎的第几页、第几条, * 所以将页号和排序信息放入兴许的CrawlDatum中,为了能够区分外链和 * 搜索引擎结果页面,我们将其pageType设置为outlink,这里的值全然由 用户定义。能够设置一个随意的值 * 在经典爬虫中,每一个网页都有一个refer信息。表示当前网页的链接来源。

    * 比如我们首先訪问新浪首页。然后从新浪首页中解析出了新的新闻链接, * 则这些网页的refer值都是新浪首页。WebCollector不直接保存refer值, * 但我们能够通过以下的方式,将refer信息保存在metaData中。达到相同的效果。 * 经典爬虫中锚文本的存储也能够通过以下方式实现。

    * 在一些需求中。希望得到当前页面在遍历树中的深度。利用metaData非常easy实现 * 这个功能,在将CrawlDatum加入到next中时,将其depth设置为当前訪问页面 的depth+1就可以。

    */ CrawlDatum datum = new CrawlDatum(result.attr("abs:href")) .putMetaData("keyword", keyword) .putMetaData("pageNum", pageNum + "") .putMetaData("rank", rank + "") .putMetaData("pageType", "outlink") .putMetaData("depth", (depth + 1) + "") .putMetaData("refer", page.getUrl()); next.add(datum); } } else if (pageType.equals("outlink")) { /*int pageNum = Integer.valueOf(page.getMetaData("pageNum")); int rank = Integer.valueOf(page.getMetaData("rank")); String refer = page.getMetaData("refer");*/ try { String content = ContentExtractor.getContentByUrl(page.getUrl()); /*String line = String.format( "第%s页第%s个结果:标题:%s(%s字节) depth=%s refer=%s", pageNum, rank + 1, page.getDoc().title(), content, depth, refer);*/ String line = String.format("标题:%s 来源:%s 正文:%s", page.getDoc().title(),page.getUrl(),content); HashMap<String, String> data = new HashMap<String,String>(); Date currentDate = new java.util.Date(); SimpleDateFormat myFmt = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); TimeZone timeZoneChina = TimeZone.getTimeZone("Asia/Shanghai");// 获取中国的时区 myFmt.setTimeZone(timeZoneChina);// 设置系统时区 String grabTime = myFmt.format(currentDate);// new Date()为获取当前系统时间 data.put("title", page.getDoc().title()); data.put("from", page.getUrl()); data.put("content", content); data.put("grabTime", grabTime); //String line = String.format("标题:%s ", page.getDoc().title()); //持久化到word文档中 //是否为线程安全??? //synchronized(this) { String destFile = "D:\"+"Result"+keyword+".doc"; result.append(line); //将result写到doc文件里 write2File(destFile,result.toString()); //加入到数据库中 addResultData(data); //} System.out.println(line); } catch (Exception e) { //e.printStackTrace(); System.out.println("链接"+page.getUrl()+"失效"); } } } //将数据保存到mysql数据库中 private void addResultData(HashMap<String, String> data) { String title = data.get("title"); String source_url = data.get("from"); String content = data.get("content").replaceAll("\?{2,}", "");//去掉字符串中出现的多个连续问号。

    //抓取时间 String grabTime = data.get("grabTime"); /*SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); Date date = null; try { date = format.parse(grabTime); } catch (Exception e) { e.printStackTrace(); }*/ //System.out.println("抓取时间"+grabTime); try { connection = DriverManager.getConnection(url, username, password); String sql = "INSERT INTO wjd_keyword_search_table(TITLE,GRAP_TIME,CONTENT,SOURCE_URL) VALUES(?,?,?

    ,?

    )"; String checkSql = "select 1 from wjd_keyword_search_table where TITLE='" + title + "'"; Statement statement = connection.prepareStatement(checkSql); ResultSet result = statement.executeQuery(checkSql); if (!result.next()) { // 假设数据库中不存在该记录,则加入到数据库中 pstatement = connection.prepareStatement(sql); pstatement.setString(1, title); //pstatement.setString(2, date); pstatement.setString(2,grabTime); pstatement.setString(3, content); pstatement.setString(4, source_url); pstatement.executeUpdate(); } } catch (SQLException e) { e.printStackTrace(); } } /** * 将数据持久化到本地doc文件里 * @param destFile * @param line */ private void write2File(String destFile, String line) { try { //doc content ByteArrayInputStream bais = new ByteArrayInputStream(line.getBytes()); POIFSFileSystem fs = new POIFSFileSystem(); DirectoryEntry directory = fs.getRoot(); directory.createDocument("WordDocument", bais); FileOutputStream ostream = new FileOutputStream(destFile); fs.writeFilesystem(ostream); bais.close(); ostream.close(); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) throws Exception { String[] keywordsList = {"网络爬虫","搜索引擎"}; int pageToal =5; for (String keyword : keywordsList) { BdiduKeywordCrawler crawler = new BdiduKeywordCrawler(keyword, pageToal); crawler.start(); } } /** * 依据关键词和页号拼接百度搜索相应的URL */ public static String createUrl(String keyword, int pageNum) throws Exception { int first = (pageNum-1) * 10; keyword = URLEncoder.encode(keyword, "utf-8"); return String.format("https://www.baidu.com/s?

    wd=%s&pn=%s", keyword, first); } }



  • 相关阅读:
    大型电商业务架构 IT大咖说
    携程开源配置中心Apollo的设计与实现 IT大咖说
    李善友《认知升级之第一性原理》--507张PPT全解!_搜狐科技_搜狐网
    http://www.educity.cn/luntan/144478_5.html
    微服务架构下的分布式数据存储-技术之家
    http://blog.longjiazuo.com/archives/3080
    实施微服务架构的关键技术
    微服务架构的分布式事务解决方案
    k8s~helm镜像版本永远不要用latest
    nginx~对没有定义service_name的三级域名进行过滤
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/8425139.html
Copyright © 2011-2022 走看看