zoukankan      html  css  js  c++  java
  • 知乎下巴第2集:使用爬虫来获取知乎的编辑推荐内容

    上一回我们拿百度做了测试,那么这一次开始做知乎下巴啦。

    首先花个三五分钟设计一个Logo=。=作为一个程序员我一直有一颗做美工的心!

    好吧做的有点小凑合,就先凑合着用咯。

    接下来呢,我们开始制作知乎的爬虫。

    首先,确定第一个目标:编辑推荐。

    网页链接:http://www.zhihu.com/explore/recommendations

    我们对上次的代码稍作修改,先实现能够获取该页面内容:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. import java.io.*;  
    2. import java.net.*;  
    3. import java.util.regex.*;  
    4.   
    5. public class Main {  
    6.     static String SendGet(String url) {  
    7.         // 定义一个字符串用来存储网页内容  
    8.         String result = "";  
    9.         // 定义一个缓冲字符输入流  
    10.         BufferedReader in = null;  
    11.   
    12.         try {  
    13.             // 将string转成url对象  
    14.             URL realUrl = new URL(url);  
    15.             // 初始化一个链接到那个url的连接  
    16.             URLConnection connection = realUrl.openConnection();  
    17.             // 开始实际的连接  
    18.             connection.connect();  
    19.             // 初始化 BufferedReader输入流来读取URL的响应  
    20.             in = new BufferedReader(new InputStreamReader(  
    21.                     connection.getInputStream()));  
    22.             // 用来临时存储抓取到的每一行的数据  
    23.             String line;  
    24.             while ((line = in.readLine()) != null) {  
    25.                 // 遍历抓取到的每一行并将其存储到result里面  
    26.                 result += line;  
    27.             }  
    28.         } catch (Exception e) {  
    29.             System.out.println("发送GET请求出现异常!" + e);  
    30.             e.printStackTrace();  
    31.         }  
    32.         // 使用finally来关闭输入流  
    33.         finally {  
    34.             try {  
    35.                 if (in != null) {  
    36.                     in.close();  
    37.                 }  
    38.             } catch (Exception e2) {  
    39.                 e2.printStackTrace();  
    40.             }  
    41.         }  
    42.         return result;  
    43.   
    44.     }  
    45.   
    46.     static String RegexString(String targetStr, String patternStr) {  
    47.         // 定义一个样式模板,此中使用正则表达式,括号中是要抓的内容  
    48.         // 相当于埋好了陷阱匹配的地方就会掉下去  
    49.         Pattern pattern = Pattern.compile(patternStr);  
    50.         // 定义一个matcher用来做匹配  
    51.         Matcher matcher = pattern.matcher(targetStr);  
    52.         // 如果找到了  
    53.         if (matcher.find()) {  
    54.             // 打印出结果  
    55.             return matcher.group(1);  
    56.         }  
    57.         return "Nothing";  
    58.     }  
    59.   
    60.     public static void main(String[] args) {  
    61.   
    62.         // 定义即将访问的链接  
    63.         String url = "http://www.zhihu.com/explore/recommendations";  
    64.         // 访问链接并获取页面内容  
    65.         String result = SendGet(url);  
    66.         // 使用正则匹配图片的src内容  
    67.         //String imgSrc = RegexString(result, "src="(.+?)"");  
    68.         // 打印结果  
    69.         System.out.println(result);  
    70.     }  
    71. }  


    运行一下木有问题,接下来就是一个正则匹配的问题了。

    首先我们先来获取该页面的所有的问题。

    右击标题,审查元素:

    啊哈,可以看到标题其实是一个a标签,也就是一个超链接,而其中能够和其他超链接区分开的,应该就是那个class了,也就是类选择器。

    于是我们的正则语句就出来了:question_link.+?href="(.+?)"

    调用RegexString函数,并给它传参:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. public static void main(String[] args) {  
    2.   
    3.     // 定义即将访问的链接  
    4.     String url = "http://www.zhihu.com/explore/recommendations";  
    5.     // 访问链接并获取页面内容  
    6.     String result = SendGet(url);  
    7.     // 使用正则匹配图片的src内容  
    8.     String imgSrc = RegexString(result, "question_link.+?>(.+?)<");  
    9.     // 打印结果  
    10.     System.out.println(imgSrc);  
    11. }  



    啊哈,可以看到我们成功抓到了一个标题(注意,只是一个):

    等一下啊这一大堆的乱七八糟的是什么玩意?!

    别紧张=。=它只是字符乱码而已。

    编码问题可以参见:HTML字符集

    一般来说,对中文支持较好的主流编码是UTF-8,GB2312和GBK编码。

    网页可以通过meta标签的charset来设置网页编码,譬如:

    [html] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. <meta charset="utf-8" />  




    我们右击,查看页面源代码:

    可以看到,知乎采用的是UTF-8编码。

    在这里和大家解释一下查看页面源代码和审查元素的区别。

    查看页面源代码是显示整个页面的所有代码,没有按照HTML的标签进行排版,相当于是直接查看源码,这种方式对于查看整个网页的信息,比如meta比较有用。

    审查元素,或者有的浏览器叫查看元素,是针对你右击的元素进行查看,比如一个div或者img,比较适用于单独查看某个对象的属性和标签。

    好的,我们现在知道了问题出在了编码上,接下来就是对抓取到的内容进行编码转换了。

    在java中实现很简单,只需要在InputStreamReader里面指定编码方式就行:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. // 初始化 BufferedReader输入流来读取URL的响应  
    2.             in = new BufferedReader(new InputStreamReader(  
    3.                     connection.getInputStream(),"UTF-8"));  



    此时再运行程序,便会发现可以正常显示标题了:

    好的!非常好!

    但是现在才只有一个标题,我们需要的是所有的标题。

    我们将正则稍加修改,把搜索到的结果存储到一个ArrayList里面:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. import java.io.*;  
    2. import java.net.*;  
    3. import java.util.ArrayList;  
    4. import java.util.regex.*;  
    5.   
    6. public class Main {  
    7.     static String SendGet(String url) {  
    8.         // 定义一个字符串用来存储网页内容  
    9.         String result = "";  
    10.         // 定义一个缓冲字符输入流  
    11.         BufferedReader in = null;  
    12.   
    13.         try {  
    14.             // 将string转成url对象  
    15.             URL realUrl = new URL(url);  
    16.             // 初始化一个链接到那个url的连接  
    17.             URLConnection connection = realUrl.openConnection();  
    18.             // 开始实际的连接  
    19.             connection.connect();  
    20.             // 初始化 BufferedReader输入流来读取URL的响应  
    21.             in = new BufferedReader(new InputStreamReader(  
    22.                     connection.getInputStream(), "UTF-8"));  
    23.             // 用来临时存储抓取到的每一行的数据  
    24.             String line;  
    25.             while ((line = in.readLine()) != null) {  
    26.                 // 遍历抓取到的每一行并将其存储到result里面  
    27.                 result += line;  
    28.             }  
    29.         } catch (Exception e) {  
    30.             System.out.println("发送GET请求出现异常!" + e);  
    31.             e.printStackTrace();  
    32.         }  
    33.         // 使用finally来关闭输入流  
    34.         finally {  
    35.             try {  
    36.                 if (in != null) {  
    37.                     in.close();  
    38.                 }  
    39.             } catch (Exception e2) {  
    40.                 e2.printStackTrace();  
    41.             }  
    42.         }  
    43.         return result;  
    44.   
    45.     }  
    46.   
    47.     static ArrayList<String> RegexString(String targetStr, String patternStr) {  
    48.         // 预定义一个ArrayList来存储结果  
    49.         ArrayList<String> results = new ArrayList<String>();  
    50.         // 定义一个样式模板,此中使用正则表达式,括号中是要抓的内容  
    51.         Pattern pattern = Pattern.compile(patternStr);  
    52.         // 定义一个matcher用来做匹配  
    53.         Matcher matcher = pattern.matcher(targetStr);  
    54.         // 如果找到了  
    55.         boolean isFind = matcher.find();  
    56.         // 使用循环将句子里所有的kelvin找出并替换再将内容加到sb里  
    57.         while (isFind) {  
    58.             //添加成功匹配的结果  
    59.             results.add(matcher.group(1));  
    60.             // 继续查找下一个匹配对象  
    61.             isFind = matcher.find();  
    62.         }  
    63.         return results;  
    64.     }  
    65.   
    66.     public static void main(String[] args) {  
    67.   
    68.         // 定义即将访问的链接  
    69.         String url = "http://www.zhihu.com/explore/recommendations";  
    70.         // 访问链接并获取页面内容  
    71.         String result = SendGet(url);  
    72.         // 使用正则匹配图片的src内容  
    73.         ArrayList<String> imgSrc = RegexString(result, "question_link.+?>(.+?)<");  
    74.         // 打印结果  
    75.         System.out.println(imgSrc);  
    76.     }  
    77. }  



    这样就能匹配到所有的结果了(因为直接打印了ArrayList所以会有一些中括号和逗号):

    OK,这样就算是完成了知乎爬虫的第一步。

    但是我们可以看出来,用这样的方式是没有办法抓到所有的问题和回答的。

    我们需要设计一个Zhihu封装类,来存储所有抓取到的对象。

    Zhihu.java源码:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. import java.util.ArrayList;  
    2.   
    3. public class Zhihu {  
    4.     public String question;// 问题  
    5.     public String zhihuUrl;// 网页链接  
    6.     public ArrayList<String> answers;// 存储所有回答的数组  
    7.   
    8.     // 构造方法初始化数据  
    9.     public Zhihu() {  
    10.         question = "";  
    11.         zhihuUrl = "";  
    12.         answers = new ArrayList<String>();  
    13.     }  
    14.   
    15.     @Override  
    16.     public String toString() {  
    17.         return "问题:" + question + " 链接:" + zhihuUrl + " 回答:" + answers + " ";  
    18.     }  
    19. }  



    再新建一个Spider类来存放一些爬虫常用的函数。

    Spider.java源码:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. import java.io.BufferedReader;  
    2. import java.io.InputStreamReader;  
    3. import java.net.URL;  
    4. import java.net.URLConnection;  
    5. import java.util.ArrayList;  
    6. import java.util.regex.Matcher;  
    7. import java.util.regex.Pattern;  
    8.   
    9. public class Spider {  
    10.     static String SendGet(String url) {  
    11.         // 定义一个字符串用来存储网页内容  
    12.         String result = "";  
    13.         // 定义一个缓冲字符输入流  
    14.         BufferedReader in = null;  
    15.   
    16.         try {  
    17.             // 将string转成url对象  
    18.             URL realUrl = new URL(url);  
    19.             // 初始化一个链接到那个url的连接  
    20.             URLConnection connection = realUrl.openConnection();  
    21.             // 开始实际的连接  
    22.             connection.connect();  
    23.             // 初始化 BufferedReader输入流来读取URL的响应  
    24.             in = new BufferedReader(new InputStreamReader(  
    25.                     connection.getInputStream(), "UTF-8"));  
    26.             // 用来临时存储抓取到的每一行的数据  
    27.             String line;  
    28.             while ((line = in.readLine()) != null) {  
    29.                 // 遍历抓取到的每一行并将其存储到result里面  
    30.                 result += line;  
    31.             }  
    32.         } catch (Exception e) {  
    33.             System.out.println("发送GET请求出现异常!" + e);  
    34.             e.printStackTrace();  
    35.         }  
    36.         // 使用finally来关闭输入流  
    37.         finally {  
    38.             try {  
    39.                 if (in != null) {  
    40.                     in.close();  
    41.                 }  
    42.             } catch (Exception e2) {  
    43.                 e2.printStackTrace();  
    44.             }  
    45.         }  
    46.         return result;  
    47.   
    48.     }  
    49.   
    50.     static ArrayList<Zhihu> GetZhihu(String content) {  
    51.         // 预定义一个ArrayList来存储结果  
    52.         ArrayList<Zhihu> results = new ArrayList<Zhihu>();  
    53.         // 用来匹配标题  
    54.         Pattern questionPattern = Pattern.compile("question_link.+?>(.+?)<");  
    55.         Matcher questionMatcher = questionPattern.matcher(content);  
    56.         // 用来匹配url,也就是问题的链接  
    57.         Pattern urlPattern = Pattern.compile("question_link.+?href="(.+?)"");  
    58.         Matcher urlMatcher = urlPattern.matcher(content);  
    59.   
    60.         // 问题和链接要均能匹配到  
    61.         boolean isFind = questionMatcher.find() && urlMatcher.find();  
    62.   
    63.         while (isFind) {  
    64.             // 定义一个知乎对象来存储抓取到的信息  
    65.             Zhihu zhuhuTemp = new Zhihu();  
    66.             zhuhuTemp.question = questionMatcher.group(1);  
    67.             zhuhuTemp.zhihuUrl = "http://www.zhihu.com" + urlMatcher.group(1);  
    68.   
    69.             // 添加成功匹配的结果  
    70.             results.add(zhuhuTemp);  
    71.             // 继续查找下一个匹配对象  
    72.             isFind = questionMatcher.find() && urlMatcher.find();  
    73.         }  
    74.         return results;  
    75.     }  
    76.   
    77. }  



    最后一个main方法负责调用。

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. import java.util.ArrayList;  
    2.   
    3. public class Main {  
    4.   
    5.     public static void main(String[] args) {  
    6.         // 定义即将访问的链接  
    7.         String url = "http://www.zhihu.com/explore/recommendations";  
    8.         // 访问链接并获取页面内容  
    9.         String content = Spider.SendGet(url);  
    10.         // 获取该页面的所有的知乎对象  
    11.         ArrayList<Zhihu> myZhihu = Spider.GetZhihu(content);  
    12.         // 打印结果  
    13.         System.out.println(myZhihu);  
    14.     }  
    15. }  


    Ok这样就算搞定了。运行一下看看结果:

    好的效果不错。

    接下来就是访问链接然后获取到所有的答案了。

    下一回我们再介绍。

  • 相关阅读:
    HDU 1124 Factorial
    hdu 1690 Bus System
    hdu 1113 Word Amalgamation
    POJ 2482 Stars in Your Window
    hdu 1385 ZOJ 1456 Minimum Transport Cost(经典floyd)
    hdu 1907 John
    VMware 虚拟机 安装 UBuntu 9.10 命令模式转换成窗口模试
    #pragma CODE_SEG __NEAR_SEG NON_BANKED详解
    Ubuntu 下Hadoop 伪分布式 hadoop0.20.2.tar.gz 的安装
    文件拷贝代码以及疑问
  • 原文地址:https://www.cnblogs.com/shareshow/p/4785458.html
Copyright © 2011-2022 走看看