• webmagic爬取博客园所有文章


    最近学习了下webmagic,学webmagic是因为想折腾下爬虫,但是自己学java的,又不想太费功夫,所以webmagic是比较好的选择了。

    写了几个demo,源码流程大致看了一遍。想着把博客园的文章列表爬下来吧。

    首页显示的就是第一页文章的列表,

    但是翻页按钮不是链接,而是动态的地址:

    实际请求的地址及参数:

    针对这个动态页面的情况,有两种解决方案:

    1. webmagic模拟post请求,获取返回页面。

     1 public class CnblogsSpider implements PageProcessor {
     2 
     3     private Site site = Site.me().setRetryTimes(3).setSleepTime(1000).setTimeOut(10000)
     4             .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36");
     5 
     6     public static final String URL_LIST = "https://www.cnblogs.com/mvc/AggSite/PostList.aspx";
     7 
     8     public static int pageNum = 1;
     9 
    10     public void process(Page page) {
    11 
    12         if (page.getUrl().regex("^https://www\.cnblogs\.com$").match()) {
    13             try {
    14                 page.addTargetRequests(page.getHtml().xpath("//*[@id="post_list"]/div/div[@class='post_item_body']/h3/a/@href").all());
    15                 pageNum++;
    16              //模拟post请求
    17                 Request req = new Request();
    18                 req.setMethod(HttpConstant.Method.POST);
    19                 req.setUrl("https://www.cnblogs.com/mvc/AggSite/PostList.aspx");
    20                 req.setRequestBody(HttpRequestBody.json("{CategoryType: 'SiteHome', ParentCategoryId: 0, CategoryId: 808, PageIndex: " + pageNum
    21                         + ", TotalPostCount: 4000,ItemListActionName:'PostList'}", "utf-8"));
    22                 page.addTargetRequest(req);
    23             } catch (Exception e) {
    24                 e.printStackTrace();
    25             }
    26         } else if (page.getUrl().regex(URL_LIST).match() && pageNum <= 200) {
    27             try {           
    28                 Thread.sleep(5000);
    29                 List<String> urls = page.getHtml().xpath("//*[@class='post_item']//div[@class='post_item_body']/h3/a/@href").all();
    30                 page.addTargetRequests(urls);
    31                 //模拟post请求
    32                 Request req = new Request();
    33                 req.setMethod(HttpConstant.Method.POST);
    34                 req.setUrl("https://www.cnblogs.com/mvc/AggSite/PostList.aspx");
    35                 req.setRequestBody(HttpRequestBody.json("{CategoryType: 'SiteHome', ParentCategoryId: 0, CategoryId: 808, PageIndex: " + ++pageNum
    36                         + ", TotalPostCount: 4000,ItemListActionName:'PostList'}", "utf-8"));
    37                 page.addTargetRequest(req);
    38                 System.out.println("CurrPage:" + pageNum + "#######################################");
    39 
    40             } catch (Exception e) {
    41                 e.printStackTrace();
    42             }
    43         } else {
    44             // 获取页面需要的内容,这里只取了标题,其他信息同理。
    45             System.out.println("抓取的内容:" + page.getHtml().xpath("//a[@id='cb_post_title_url']/text()").get());
    46         }
    47     }
    48 
    49     public Site getSite() {
    50         return site;
    51     }
    52 
    53     public static void main(String[] args) {
    54         Spider.create(new CnblogsSpider()).addUrl("https://www.cnblogs.com").thread(3).run();
    55     }
    56 }

    2.使用webmagic-selenium 

     1 public class SeleniumCnblogsSpider implements PageProcessor {
     2 
     3     private Site site = Site.me().setRetryTimes(3).setSleepTime(1000).setTimeOut(10000)
     4             .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36");
     5 
     6     public static final String URL_LIST = "https://www\.cnblogs\.com/#p\d{1,3}";
     7 
     8     public static int pageNum = 1;
     9 
    10     public void process(Page page) {
    11 
    12         
    13         if (page.getUrl().regex("^https://www\.cnblogs\.com$").match()) {//爬取第一页
    14             try {
    15                 page.addTargetRequests(page.getHtml().xpath("//*[@id="post_list"]/div/div[@class='post_item_body']/h3/a/@href").all());
    16 
    17                 pageNum++;
    18                 page.addTargetRequest("https://www.cnblogs.com/#p2");
    19             } catch (Exception e) {
    20                 e.printStackTrace();
    21             }
    22         } else if (page.getUrl().regex(URL_LIST).match() && pageNum <= 200) {//爬取2-200页,一共有200页
    23             try {
    24                 List<String> urls = page.getHtml().xpath("//*[@class='post_item']//div[@class='post_item_body']/h3/a/@href").all();
    25                 page.addTargetRequests(urls);
    26 
    27                 page.addTargetRequest("https://www.cnblogs.com/#p" + ++pageNum);
    28                 System.out.println("CurrPage:" + pageNum + "#######################################");
    29 
    30             } catch (Exception e) {
    31                 e.printStackTrace();
    32             }
    33         } else {
    34             // 获取页面需要的内容
    35             System.out.println("抓取的内容:" + page.getHtml().xpath("//a[@id='cb_post_title_url']/text()").get());
    36         }
    37     }
    38 
    39     public Site getSite() {
    40         return site;
    41     }
    42 
    43     public static void main(String[] args) {
    44         System.setProperty("selenuim_config", "D:/config.ini");//配置文件,我用的webmagic0.7.2,低版本可能不需要该文件,但也不支持phantomjs.
    45         Downloader downloader = new SeleniumDownloader();//调用seleniumdownloader,这个downlaoder可以驱动selenium,phantomjs等方式下载,由config.ini配置
    46         downloader.setThread(10);
    47         Spider.create(new SeleniumCnblogsSpider()).setDownloader(downloader).addUrl("https://www.cnblogs.com").thread(10).runAsync();
    48     }
    49 }

    另附我的config.ini和pom文件:

     1 # What WebDriver to use for the tests
     2 driver=phantomjs
     3 #driver=firefox
     4 #driver=chrome
     5 #driver=http://localhost:8910
     6 #driver=http://localhost:4444/wd/hub
     7 
     8 # PhantomJS specific config (change according to your installation)
     9 #phantomjs_exec_path=/Users/Bingo/bin/phantomjs-qt5
    10 phantomjs_exec_path=d:/phantomjs.exe
    11 #phantomjs_driver_path=/Users/Bingo/Documents/workspace/webmagic/webmagic-selenium/src/main.js
    12 phantomjs_driver_loglevel=DEBUG
     1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     2     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     3     <modelVersion>4.0.0</modelVersion>
     4     <groupId>com.summit</groupId>
     5     <artifactId>WebMagicDemo</artifactId>
     6     <version>0.0.1-SNAPSHOT</version>
     7 
     8     <dependencies>
     9         <dependency>
    10             <groupId>us.codecraft</groupId>
    11             <artifactId>webmagic-core</artifactId>
    12             <version>0.7.2</version>
    13         </dependency>
    14         <dependency>
    15             <groupId>us.codecraft</groupId>
    16             <artifactId>webmagic-extension</artifactId>
    17             <version>0.7.2</version>
    18         </dependency>
    19         <dependency>
    20             <groupId>us.codecraft</groupId>
    21             <artifactId>webmagic-selenium</artifactId>
    22             <version>0.7.2</version>
    23         </dependency>
    24         <dependency>
    25             <groupId>org.seleniumhq.selenium</groupId>
    26             <artifactId>selenium-java</artifactId>
    27             <version>2.41.0</version>
    28         </dependency>
    29     </dependencies>
    30 </project>

    如果依赖版本与此不一致,可能会出问题。

    后记:

      本文主要记录了我在解决webmagic爬取动态页面的心得。

      方法1在可以获取动态访问地址的情况下用,比如通过调试工具,我可以找到第二页实际的访问地址是:https://www.cnblogs.com/mvc/AggSite/PostList.aspx,用这种方法实测效率比较高。但复杂场景下不推荐。

      方法2主要是针对复杂场景,在实际地址很难找或者隐藏,网站有反扒措施的情况下通常很好用,因为它是模拟的实际的浏览器,比较耗费资源,效率比方法1低 。  

      webmagic0.7.2 支持selenium (chrome),phantomjs的模拟浏览器行为的方式获取页面。我在方法2中使用的是phantomjs下载的。selenium 的方式我也试过,但是每次调用下载就会弹出浏览器窗口,很是不爽,也没找到如何解决,所以就不推荐了。

    抓取结果截图:

     

  • 相关阅读:
    linux下ssh使用
    CentOS 5.3使用minicom
    CentOS mysql
    CentOS下使用vsftpd
    Python处理json字符串转化为字典
    自己写的C#扫雷游戏(附源码)
    新伙伴
    成就了儿时一个简单的想法
    Sun VirtualBox vs. VMware Workstation
    DVDLogger源码——SQLite简单应用
  • 原文地址:https://www.cnblogs.com/tibit/p/7136762.html
Copyright © 2020-2023  润新知