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 的方式我也试过,但是每次调用下载就会弹出浏览器窗口,很是不爽,也没找到如何解决,所以就不推荐了。

抓取结果截图:

 

原文地址:https://www.cnblogs.com/tibit/p/7136762.html