`
wbj0110
  • 浏览: 1550634 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

使用Java调用百度搜索(转)

阅读更多

search-demo托管于github

 

search-demo演示了如何利用Java来调用百度搜索和谷歌搜索,更多细节请到github上查看search-demo

 

自己没搜索引擎,又想要大规模的数据源,怎么办?可以对百度搜索和谷歌搜索善加利用,以小搏大,站在巨人的肩膀上。有很多的应用场景可以很巧妙地借助百度搜索和谷歌搜索来实现,比如网站的新闻采集,比如技术、品牌的新闻跟踪,比如知识库的收集,比如人机问答系统等,我之前做的一个准确率达百分之九十几的人机问答系统的数据源,其中一部分就是充分利用了百度搜索和谷歌搜索。在此演示的技术的基础上,可以容易地扩展到其他的搜索引擎,可以借鉴使用的NekoHTML+XPath或JSoup+CSSPath技术,轻松获取页面的自定义的内容。

 

实现方式一:NekoHTML+XPath

 

Java代码   收藏代码
  1. package org.apdplat.demo.search;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.ByteArrayInputStream;  
  5. import java.io.IOException;  
  6. import java.io.InputStream;  
  7. import java.io.InputStreamReader;  
  8. import java.io.UnsupportedEncodingException;  
  9. import java.net.URL;  
  10. import java.util.ArrayList;  
  11. import java.util.HashMap;  
  12. import java.util.List;  
  13. import java.util.Map;  
  14.   
  15. import org.cyberneko.html.parsers.DOMParser;  
  16. import org.slf4j.Logger;  
  17. import org.slf4j.LoggerFactory;  
  18. import org.w3c.dom.Document;  
  19. import org.w3c.dom.Node;  
  20. import org.w3c.dom.NodeList;  
  21. import org.xml.sax.InputSource;  
  22.   
  23. import com.sun.org.apache.xpath.internal.XPathAPI;  
  24. import javax.xml.transform.TransformerException;  
  25. import org.w3c.dom.DOMException;  
  26. import org.xml.sax.SAXException;  
  27.   
  28. public class NekoHTMLBaiduSearcher implements Searcher{  
  29.     private static final Logger LOG = LoggerFactory.getLogger(NekoHTMLBaiduSearcher.class);  
  30.   
  31.     public List<String> parse(String url, String xpathExpression) {  
  32.         InputStream in = null;  
  33.         try {  
  34.             in = new URL(url).openStream();  
  35.             return parse(in, xpathExpression);  
  36.         } catch (Exception e) {  
  37.             LOG.error("错误", e);  
  38.         } finally {  
  39.             if (in != null) {  
  40.                 try {  
  41.                     in.close();  
  42.                 } catch (IOException e) {  
  43.                     LOG.error("错误", e);  
  44.                 }  
  45.             }  
  46.         }  
  47.         return null;  
  48.     }  
  49.   
  50.     public List<String> parse(InputStream in, String xpathExpression) {  
  51.         return parse(in, xpathExpression, "UTF-8");  
  52.     }  
  53.   
  54.     public List<Map<String, String>> parseMore(InputStream in, String xpathExpression) {  
  55.         return parseMore(in, xpathExpression, "UTF-8");  
  56.     }  
  57.   
  58.     public List<Map<String, String>> parseMore(InputStream in, String xpathExpression, String encoding) {  
  59.         DOMParser parser = new DOMParser();  
  60.         List<Map<String, String>> list = new ArrayList<>();  
  61.         try {  
  62.             // 设置网页的默认编码  
  63.             parser.setProperty(  
  64.                     "http://cyberneko.org/html/properties/default-encoding",  
  65.                     encoding);  
  66.             /* 
  67.              * The Xerces HTML DOM implementation does not support namespaces 
  68.              * and cannot represent XHTML documents with namespace information. 
  69.              * Therefore, in order to use the default HTML DOM implementation 
  70.              * with NekoHTML's DOMParser to parse XHTML documents, you must turn 
  71.              * off namespace processing. 
  72.              */  
  73.             parser.setFeature("http://xml.org/sax/features/namespaces"false);  
  74.             parser.parse(new InputSource(new BufferedReader(new InputStreamReader(in, encoding))));  
  75.             Document doc = parser.getDocument();  
  76.             NodeList products = XPathAPI.selectNodeList(doc, xpathExpression.toUpperCase());  
  77.             for (int i = 0; i < products.getLength(); i++) {  
  78.                 Node node = products.item(i);  
  79.                 String title = node.getTextContent();  
  80.                 Map<String, String> map = new HashMap<>();  
  81.                 map.put("title", title);  
  82.                 try {  
  83.                     String href = node.getAttributes().getNamedItem("href").getTextContent();  
  84.                     map.put("href", href);  
  85.                 } catch (Exception e) {  
  86.                     LOG.error("提取链接失败",e);  
  87.                 }  
  88.                 list.add(map);  
  89.             }  
  90.         } catch (SAXException | IOException | TransformerException | DOMException e) {  
  91.             LOG.error("错误", e);  
  92.         }  
  93.         return list;  
  94.     }  
  95.   
  96.     public List<String> parse(InputStream in, String xpathExpression, String encoding) {  
  97.         DOMParser parser = new DOMParser();  
  98.         List<String> list = new ArrayList<>();  
  99.         try {  
  100.             // 设置网页的默认编码  
  101.             parser.setProperty(  
  102.                     "http://cyberneko.org/html/properties/default-encoding",  
  103.                     encoding);  
  104.             /* 
  105.              * The Xerces HTML DOM implementation does not support namespaces 
  106.              * and cannot represent XHTML documents with namespace information. 
  107.              * Therefore, in order to use the default HTML DOM implementation 
  108.              * with NekoHTML's DOMParser to parse XHTML documents, you must turn 
  109.              * off namespace processing. 
  110.              */  
  111.             parser.setFeature("http://xml.org/sax/features/namespaces"false);  
  112.             parser.parse(new InputSource(new BufferedReader(new InputStreamReader(in, encoding))));  
  113.             Document doc = parser.getDocument();  
  114.             NodeList products = XPathAPI.selectNodeList(doc, xpathExpression.toUpperCase());  
  115.             for (int i = 0; i < products.getLength(); i++) {  
  116.                 Node node = products.item(i);  
  117.                 list.add(node.getTextContent());  
  118.             }  
  119.         } catch (SAXException | IOException | TransformerException | DOMException e) {  
  120.             LOG.error("错误", e);  
  121.         }  
  122.         return list;  
  123.     }  
  124.   
  125.     @Override  
  126.     public List<Webpage> search(String url) {  
  127.         InputStream in = null;  
  128.         try {  
  129.             in = new URL(url).openStream();  
  130.             return search(in);  
  131.         } catch (Exception e) {  
  132.             LOG.error("错误", e);  
  133.         } finally {  
  134.             if (in != null) {  
  135.                 try {  
  136.                     in.close();  
  137.                 } catch (IOException e) {  
  138.                     LOG.error("错误", e);  
  139.                 }  
  140.             }  
  141.         }  
  142.         return null;  
  143.     }  
  144.   
  145.     public List<Webpage> search(InputStream in) {  
  146.         //保证只读一次  
  147.         byte[] datas = Tools.readAll(in);  
  148.         if (LOG.isDebugEnabled()) {  
  149.             try {  
  150.                 LOG.debug("内容:" + new String(datas, "UTF-8"));  
  151.             } catch (UnsupportedEncodingException e) {  
  152.                 LOG.error("错误", e);  
  153.             }  
  154.         }  
  155.   
  156.         in = new ByteArrayInputStream(datas);  
  157.   
  158.         String totalXpathExpression = "//html/body/div/div/div/div[3]/p/span";  
  159.         List<String> totals = parse(in, totalXpathExpression);  
  160.         int total;  
  161.         int len = 10;  
  162.         if (totals != null && totals.size() == 1) {  
  163.             String str = totals.get(0);  
  164.             int start = 10;  
  165.             if (str.indexOf("约") != -1) {  
  166.                 start = 11;  
  167.             }  
  168.             total = Integer.parseInt(str.substring(start).replace(",""").replace("个"""));  
  169.             LOG.info("搜索结果数:" + total);  
  170.         } else {  
  171.             return null;  
  172.         }  
  173.         if (total < 1) {  
  174.             return null;  
  175.         }  
  176.         if (total < 10) {  
  177.             len = total;  
  178.         }  
  179.         List<Webpage> webpages = new ArrayList<>();  
  180.         for (int i = 0; i < len; i++) {  
  181.             String content = "";  
  182.             String url = "";  
  183.             String titleXpathExpression = "//html/body/div/div/div/div[3]/div[2]/table[" + (i + 1) + "]/tbody/tr/td/h3/a";  
  184.             String summaryXpathExpression = "//html/body/div/div/div/div[3]/div[2]/table[" + (i + 1) + "]/tbody/tr/td/div[1]";  
  185.             LOG.debug("titleXpathExpression:" + titleXpathExpression);  
  186.             LOG.debug("summaryXpathExpression:" + summaryXpathExpression);  
  187.             //重新构造输入流  
  188.             in = new ByteArrayInputStream(datas);  
  189.             List<String> titles = parse(in, titleXpathExpression);  
  190.   
  191.             //重新构造输入流  
  192.             in = new ByteArrayInputStream(datas);  
  193.             List<Map<String, String>> titleWithHrefs = parseMore(in, titleXpathExpression);  
  194.             for (Map<String, String> titleWithHref : titleWithHrefs) {  
  195.                 String title = titleWithHref.get("title");  
  196.                 String href = titleWithHref.get("href");  
  197.                 LOG.debug(title + " " + titleWithHref.get("href"));  
  198.                 if (href != null) {  
  199.                     content = Tools.getHTMLContent(href);  
  200.                     url = href;  
  201.                 } else {  
  202.                     LOG.info("页面正确提取失败");  
  203.                 }  
  204.             }  
  205.   
  206.             //重新构造输入流  
  207.             in = new ByteArrayInputStream(datas);  
  208.             List<String> summaries = parse(in, summaryXpathExpression);  
  209.             //处理百度知道1  
  210.             if (titles != null && titles.size() == 1 && (summaries == null || summaries.isEmpty())) {  
  211.                 //重新构造输入流  
  212.                 in = new ByteArrayInputStream(datas);  
  213.                 String baiduZhidao1XpathExpression = "//html/body/div/div/div/div[3]/div[2]/table[" + (i + 1) + "]/tbody/tr/td/font[2]/div/div/p[2]";  
  214.                 LOG.debug("baiduZhidao1XpathExpression:" + baiduZhidao1XpathExpression);  
  215.                 summaries = parse(in, baiduZhidao1XpathExpression);  
  216.             }  
  217.             //处理百度知道2  
  218.             if (titles != null && titles.size() == 1 && (summaries == null || summaries.isEmpty())) {  
  219.                 //重新构造输入流  
  220.                 in = new ByteArrayInputStream(datas);  
  221.                 String baiduZhidao2XpathExpression = "//html/body/div/div/div/div[3]/div[2]/table[" + (i + 1) + "]/tbody/tr/td/font[2]";  
  222.                 LOG.debug("baiduZhidao2XpathExpression:" + baiduZhidao2XpathExpression);  
  223.                 summaries = parse(in, baiduZhidao2XpathExpression);  
  224.             }  
  225.             //处理百度文库  
  226.             if (titles != null && titles.size() == 1 && (summaries == null || summaries.isEmpty())) {  
  227.                 //重新构造输入流  
  228.                 in = new ByteArrayInputStream(datas);  
  229.                 String baiduWenkuXpathExpression = "//html/body/div/div/div/div[3]/div[2]/table[" + (i + 1) + "]/tbody/tr/td/font[1]";  
  230.                 LOG.debug("baiduWenkuXpathExpression:" + baiduWenkuXpathExpression);  
  231.                 summaries = parse(in, baiduWenkuXpathExpression);  
  232.             }  
  233.   
  234.             if (titles != null && titles.size() == 1 && summaries != null && summaries.size() == 1) {  
  235.                 Webpage webpage = new Webpage();  
  236.                 webpage.setTitle(titles.get(0));  
  237.                 webpage.setUrl(url);  
  238.                 webpage.setSummary(summaries.get(0));  
  239.                 webpage.setContent(content);  
  240.                 webpages.add(webpage);  
  241.             } else {  
  242.                 LOG.error("获取搜索结果列表项出错:" + titles + " - " + summaries);  
  243.             }  
  244.         }  
  245.         if(webpages.size() < 10){              
  246.             //处理百度百科  
  247.             String titleXpathExpression = "//html/body/div/div/div/div[3]/div[2]/div/h3/a";  
  248.             String summaryXpathExpression = "//html/body/div/div/div/div[3]/div[2]/div/div/p";  
  249.             LOG.debug("处理百度百科 titleXpathExpression:" + titleXpathExpression);  
  250.             LOG.debug("处理百度百科 summaryXpathExpression:" + summaryXpathExpression);  
  251.             //重新构造输入流  
  252.             in = new ByteArrayInputStream(datas);  
  253.             List<String> titles = parse(in, titleXpathExpression);  
  254.             //重新构造输入流  
  255.             in = new ByteArrayInputStream(datas);  
  256.             List<Map<String, String>> titleWithHrefs = parseMore(in, titleXpathExpression);  
  257.             String content = "";  
  258.             String url = "";  
  259.             for (Map<String, String> titleWithHref : titleWithHrefs) {  
  260.                 String title = titleWithHref.get("title");  
  261.                 String href = titleWithHref.get("href");  
  262.                 LOG.debug(title + " " + titleWithHref.get("href"));  
  263.                 if (href != null) {  
  264.                     content = Tools.getHTMLContent(href);  
  265.                     url = href;  
  266.                 } else {  
  267.                     LOG.info("页面正确提取失败");  
  268.                 }  
  269.             }  
  270.             //重新构造输入流  
  271.             in = new ByteArrayInputStream(datas);  
  272.             List<String> summaries = parse(in, summaryXpathExpression);  
  273.             if (titles != null && titles.size() == 1 && summaries != null && summaries.size() == 1) {  
  274.                 Webpage webpage = new Webpage();  
  275.                 webpage.setTitle(titles.get(0));  
  276.                 webpage.setUrl(url);  
  277.                 webpage.setSummary(summaries.get(0));  
  278.                 webpage.setContent(content);  
  279.                 webpages.add(webpage);  
  280.             } else {  
  281.                 LOG.error("获取搜索结果列表项出错:" + titles + " - " + summaries);  
  282.             }  
  283.         }  
  284.         if (webpages.isEmpty()) {  
  285.             return null;  
  286.         }  
  287.         return webpages;  
  288.     }  
  289.   
  290.     public static void main(String[] args) {  
  291.         String url = "http://www.baidu.com/s?pn=0&wd=杨尚川";  
  292.           
  293.         Searcher searcher = new NekoHTMLBaiduSearcher();  
  294.         List<Webpage> webpages = searcher.search(url);  
  295.         if (webpages != null) {  
  296.             int i = 1;  
  297.             for (Webpage webpage : webpages) {  
  298.                 LOG.info("搜索结果 " + (i++) + " :");  
  299.                 LOG.info("标题:" + webpage.getTitle());  
  300.                 LOG.info("URL:" + webpage.getUrl());  
  301.                 LOG.info("摘要:" + webpage.getSummary());  
  302.                 LOG.info("正文:" + webpage.getContent());  
  303.                 LOG.info("");  
  304.             }  
  305.         } else {  
  306.             LOG.error("没有搜索到结果");  
  307.         }  
  308.     }  
  309. }  

 

 

实现方式二:JSoup+CSSPath

 

Java代码   收藏代码
  1. package org.apdplat.demo.search;  
  2.   
  3. import java.io.IOException;  
  4. import java.util.ArrayList;  
  5. import java.util.List;  
  6. import org.jsoup.Jsoup;  
  7. import org.jsoup.nodes.Document;  
  8. import org.jsoup.nodes.Element;  
  9.   
  10. import org.slf4j.Logger;  
  11. import org.slf4j.LoggerFactory;  
  12.   
  13. public class JSoupBaiduSearcher implements Searcher{  
  14.     private static final Logger LOG = LoggerFactory.getLogger(JSoupBaiduSearcher.class);  
  15.   
  16.     @Override  
  17.     public List<Webpage> search(String url) {  
  18.         List<Webpage> webpages = new ArrayList<>();  
  19.         try {  
  20.             Document document = Jsoup.connect(url).get();  
  21.             String cssQuery = "html body div#out div#in div#wrapper div#container.container_s p#page span.nums";  
  22.             LOG.debug("total cssQuery: " + cssQuery);  
  23.             Element totalElement = document.select(cssQuery).first();  
  24.             String totalText = totalElement.text();   
  25.             LOG.info("搜索结果:" + totalText);  
  26.             int start = 10;  
  27.             if (totalText.indexOf("约") != -1) {  
  28.                 start = 11;  
  29.             }  
  30.             int total = Integer.parseInt(totalText.substring(start).replace(",""").replace("个"""));  
  31.             LOG.info("搜索结果数:" + total);  
  32.             int len = 10;  
  33.             if (total < 1) {  
  34.                 return null;  
  35.             }  
  36.             if (total < 10) {  
  37.                 len = total;  
  38.             }  
  39.             for (int i = 0; i < len; i++) {  
  40.                 String titleCssQuery = "html body div#out div#in div#wrapper div#container.container_s div#content_left table#" + (i + 1) + ".result tbody tr td.c-default h3.t a";  
  41.                 String summaryCssQuery = "html body div#out div#in div#wrapper div#container.container_s div#content_left table#" + (i + 1) + ".result tbody tr td.c-default div.c-abstract";  
  42.                 LOG.debug("titleCssQuery:" + titleCssQuery);  
  43.                 LOG.debug("summaryCssQuery:" + summaryCssQuery);  
  44.                 Element titleElement = document.select(titleCssQuery).first();  
  45.                 String href = "";  
  46.                 String titleText = "";  
  47.                 if(titleElement != null){  
  48.                     titleText = titleElement.text();  
  49.                     href = titleElement.attr("href");  
  50.                 }else{  
  51.                     //处理百度百科  
  52.                     titleCssQuery = "html body div#out div#in div#wrapper div#container.container_s div#content_left div#1.result-op h3.t a";  
  53.                     summaryCssQuery = "html body div#out div#in div#wrapper div#container.container_s div#content_left div#1.result-op div p";  
  54.                     LOG.debug("处理百度百科 titleCssQuery:" + titleCssQuery);  
  55.                     LOG.debug("处理百度百科 summaryCssQuery:" + summaryCssQuery);  
  56.                     titleElement = document.select(titleCssQuery).first();  
  57.                     if(titleElement != null){  
  58.                         titleText = titleElement.text();  
  59.                         href = titleElement.attr("href");  
  60.                     }  
  61.                 }  
  62.                 LOG.debug(titleText);  
  63.                 Element summaryElement = document.select(summaryCssQuery).first();  
  64.                 //处理百度知道  
  65.                 if(summaryElement == null){  
  66.                     summaryCssQuery = summaryCssQuery.replace("div.c-abstract","font");  
  67.                     LOG.debug("处理百度知道 summaryCssQuery:" + summaryCssQuery);  
  68.                     summaryElement = document.select(summaryCssQuery).first();  
  69.                 }  
  70.                 String summaryText = "";  
  71.                 if(summaryElement != null){  
  72.                     summaryText = summaryElement.text();   
  73.                 }  
  74.                 LOG.debug(summaryText);                  
  75.                   
  76.                 if (titleText != null && !"".equals(titleText.trim()) && summaryText != null && !"".equals(summaryText.trim())) {  
  77.                     Webpage webpage = new Webpage();  
  78.                     webpage.setTitle(titleText);  
  79.                     webpage.setUrl(href);  
  80.                     webpage.setSummary(summaryText);  
  81.                     if (href != null) {  
  82.                         String content = Tools.getHTMLContent(href);  
  83.                         webpage.setContent(content);  
  84.                     } else {  
  85.                         LOG.info("页面正确提取失败");  
  86.                     }  
  87.                     webpages.add(webpage);  
  88.                 } else {  
  89.                     LOG.error("获取搜索结果列表项出错:" + titleText + " - " + summaryText);  
  90.                 }  
  91.             }  
  92.               
  93.               
  94.         } catch (IOException ex) {  
  95.             LOG.error("搜索出错",ex);  
  96.         }  
  97.         return webpages;  
  98.     }  
  99.   
  100.     public static void main(String[] args) {  
  101.         String url = "http://www.baidu.com/s?pn=0&wd=杨尚川";  
  102.           
  103.         Searcher searcher = new JSoupBaiduSearcher();  
  104.         List<Webpage> webpages = searcher.search(url);  
  105.         if (webpages != null) {  
  106.             int i = 1;  
  107.             for (Webpage webpage : webpages) {  
  108.                 LOG.info("搜索结果 " + (i++) + " :");  
  109.                 LOG.info("标题:" + webpage.getTitle());  
  110.                 LOG.info("URL:" + webpage.getUrl());  
  111.                 LOG.info("摘要:" + webpage.getSummary());  
  112.                 LOG.info("正文:" + webpage.getContent());  
  113.                 LOG.info("");  
  114.             }  
  115.         } else {  
  116.             LOG.error("没有搜索到结果");  
  117.         }  
  118.     }  
  119. }  

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics