转载: webmagic两种爬取解决方案
本文来源: https://www.cnblogs.com/tibit/p/7136762.html
最近学习了下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 的方式我也试过,但是每次调用下载就会弹出浏览器窗口,很是不爽,也没找到如何解决,所以就不推荐了。
抓取结果截图:



浙公网安备 33010602011771号