整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          WebMagic 實現爬蟲入門教程

          WebMagic 實現爬蟲入門教程

          示例實現某電影網站最新片源名稱列表及詳情頁下載地址的抓取。

          webmagic是一個開源的Java垂直爬蟲框架,目標是簡化爬蟲的開發流程,讓開發者專注于邏輯功能的開發。

          WebMagic 特點:

          • 完全模塊化的設計,強大的可擴展性。
          • 核心簡單但是涵蓋爬蟲的全部流程,靈活而強大,也是學習爬蟲入門的好材料。
          • 提供豐富的抽取頁面API。
          • 無配置,但是可通過POJO+注解形式實現一個爬蟲。
          • 支持多線程。
          • 支持分布式。
          • 支持爬取js動態渲染的頁面。
          • 無框架依賴,可以靈活的嵌入到項目中去。

          示例

          本示例實現:https://www.dytt8.net/html/gndy/dyzz/list231.html 電影網站最新片源名稱及詳情頁影片下載鏈接內容的抓取。

          配置Maven依賴

          pom.xml配置,這里因為日志文件和spring boot沖突了,所以移除webmagic的日志依賴 log4j12

          <?xml version="1.0" encoding="UTF-8"?>
          <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
           <modelVersion>4.0.0</modelVersion>
           <parent>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-parent</artifactId>
           <version>2.1.9.RELEASE</version>
           <relativePath/> <!-- lookup parent from repository -->
           </parent>
           <groupId>com.easy</groupId>
           <artifactId>webmagic</artifactId>
           <version>0.0.1</version>
           <name>webmagic</name>
           <description>Demo project for Spring Boot</description>
          
           <properties>
           <java.version>1.8</java.version>
           <encoding>UTF-8</encoding>
           <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
           <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
           </properties>
          
           <dependencies>
           <dependency>
           <groupId>us.codecraft</groupId>
           <artifactId>webmagic-core</artifactId>
           <version>0.7.3</version>
           <exclusions>
           <exclusion>
           <groupId>org.slf4j</groupId>
           <artifactId>slf4j-log4j12</artifactId>
           </exclusion>
           </exclusions>
           </dependency>
           <dependency>
           <groupId>us.codecraft</groupId>
           <artifactId>webmagic-extension</artifactId>
           <version>0.7.3</version>
           </dependency>
          
           <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
           </dependency>
          
           <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-test</artifactId>
           <scope>test</scope>
           </dependency>
           
           <dependency>
           <groupId>org.projectlombok</groupId>
           <artifactId>lombok</artifactId>
           <scope>compile</scope>
           </dependency>
           </dependencies>
          
           <build>
           <plugins>
           <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-compiler-plugin</artifactId>
           <configuration>
           <source>1.8</source>
           <target>1.8</target>
           </configuration>
           </plugin>
           </plugins>
           </build>
          
          </project>
          

          創建列表及詳情頁解析類

          PageProcessor負責解析頁面,抽取有用信息,以及發現新的鏈接。WebMagic使用Jsoup作為HTML解析工具,并基于其開發了解析XPath的工具Xsoup。

          ListPageProcesser.java 實現影片名稱列表獲取

          package com.easy.webmagic.controller;
          
          import us.codecraft.webmagic.Page;
          import us.codecraft.webmagic.Site;
          import us.codecraft.webmagic.processor.PageProcessor;
          
          public class ListPageProcesser implements PageProcessor {
           private Site site=Site.me().setDomain("127.0.0.1");
          
           @Override
           public void process(Page page) {
           page.putField("title", page.getHtml().xpath("//a[@class='ulink']").all().toString());
           }
          
           @Override
           public Site getSite() {
           return site;
           }
          }

          DetailPageProcesser.java 實現詳情頁影片下載地址獲取

          package com.easy.webmagic.controller;
          
          import us.codecraft.webmagic.Page;
          import us.codecraft.webmagic.Site;
          import us.codecraft.webmagic.processor.PageProcessor;
          
          public class DetailPageProcesser implements PageProcessor {
           private Site site=Site.me().setDomain("127.0.0.1");
          
           @Override
           public void process(Page page) {
           page.putField("download", page.getHtml().xpath("//*[@id=\"Zoom\"]/span/table/tbody/tr/td/a").toString());
           }
          
           @Override
           public Site getSite() {
           return site;
           }
          }
          

          使用Pipeline處理抓取結果

          Pipeline負責抽取結果的處理,包括計算、持久化到文件、數據庫等。WebMagic默認提供了“輸出到控制臺”和“保存到文件”兩種結果處理方案。

          Pipeline定義了結果保存的方式,如果你要保存到指定數據庫,則需要編寫對應的Pipeline。對于一類需求一般只需編寫一個Pipeline。

          這里不做任何處理,直接把抓包到的結果在控制臺輸出

          MyPipeline.java

          package com.easy.webmagic.controller;
          
          import lombok.extern.slf4j.Slf4j;
          import us.codecraft.webmagic.ResultItems;
          import us.codecraft.webmagic.Task;
          import us.codecraft.webmagic.pipeline.Pipeline;
          
          import java.util.Map;
          
          @Slf4j
          public class MyPipeline implements Pipeline {
           @Override
           public void process(ResultItems resultItems, Task task) {
           log.info("get page: " + resultItems.getRequest().getUrl());
           for (Map.Entry<String, Object> entry : resultItems.getAll().entrySet()) {
           log.info(entry.getKey() + ":\t" + entry.getValue());
           }
           }
          }

          啟動抓包入口

          Main.java

          package com.easy.webmagic.controller;
          
          import us.codecraft.webmagic.Spider;
          
          public class Main {
           public static void main(String[] args) {
           //獲取影片標題和頁面鏈接
           Spider.create(new ListPageProcesser()).addUrl("https://www.dytt8.net/html/gndy/dyzz/list_23_1.html")
           .addPipeline(new MyPipeline()).thread(1).run();
          
           //獲取指定詳情頁面的影片下載地址
           Spider.create(new DetailPageProcesser()).addUrl("https://www.dytt8.net/html/gndy/dyzz/20191204/59453.html")
           .addPipeline(new MyPipeline()).thread(1).run();
           }
          }

          運行示例

          啟動運行Main.java,觀察控制臺

          影片第一頁標題列表

          14:06:28.704 [pool-1-thread-1] INFO com.easy.webmagic.controller.MyPipeline - get page: https://www.dytt8.net/html/gndy/dyzz/list_23_1.html
          14:06:28.704 [pool-1-thread-1] INFO com.easy.webmagic.controller.MyPipeline - title: [<a href="/html/gndy/dyzz/20191204/59453.html" class="ulink">2019年劇情《中國機長》HD國語中英雙字</a>, <a href="/html/gndy/dyzz/20191201/59437.html" class="ulink">2019年動畫喜劇《雪人奇緣》BD中英雙字幕</a>, <a href="/html/gndy/dyzz/20191201/59435.html" class="ulink">2019年喜劇《伯納黛特你去了哪》BD中英雙字幕</a>, <a href="/html/gndy/dyzz/20191129/59431.html" class="ulink">2019年高分劇情《愛爾蘭人/愛爾蘭殺手》BD中英雙字幕</a>, <a href="/html/gndy/dyzz/20191129/59429.html" class="ulink">2019年劇情《唐頓莊園電影版》BD中英雙字[修正字幕]</a>, <a href="/html/gndy/dyzz/20191129/59428.html" class="ulink">2018年懸疑動作《雪暴》BD國語中字</a>, <a href="/html/gndy/dyzz/20191128/59427.html" class="ulink">2019年劇情驚悚《官方機密》BD中英雙字幕</a>, <a href="/html/gndy/dyzz/20191127/59425.html" class="ulink">2019年高分劇情《少年的你》HD國語中字</a>, <a href="/html/gndy/dyzz/20191126/59424.html" class="ulink">2019年劇情冒險《攀登者》HD國語中英雙字</a>, <a href="/html/gndy/dyzz/20191126/59423.html" class="ulink">2019年劇情《金翅雀》BD中英雙字幕</a>, <a href="/html/gndy/dyzz/20191125/59422.html" class="ulink">2019年高分獲獎《好萊塢往事》BD中英雙字幕</a>, <a href="/html/gndy/dyzz/20191125/59421.html" class="ulink">2018年動畫冒險《貓與桃花源》BD國粵雙語中字</a>, <a href="/html/gndy/dyzz/20191124/59418.html" class="ulink">2019年恐怖《準備好了沒/弒婚游戲》BD中英雙字幕</a>, <a href="/html/gndy/dyzz/20191124/59417.html" class="ulink">2019年劇情懸疑《雙魂》BD國粵雙語中字</a>, <a href="/html/gndy/dyzz/20191122/59409.html" class="ulink">2019年科幻動作《雙子殺手》HD中英雙字幕</a>, <a href="/html/gndy/dyzz/20191122/59408.html" class="ulink">2019年奇幻《天堂山/天堂山?f》BD中英雙字幕</a>, <a href="/html/gndy/dyzz/20191121/59407.html" class="ulink">2019年恐怖《小丑回魂2》BD中英雙字幕</a>, <a href="/html/gndy/dyzz/20191117/59403.html" class="ulink">2019年高分動畫《克勞斯:圣誕節的秘密》BD國英西三語雙字</a>, <a href="/html/gndy/dyzz/20191116/59400.html" class="ulink">2019年動作《天使陷落》BD中英雙字幕</a>, <a href="/html/gndy/dyzz/20191115/59399.html" class="ulink">2019年懸疑驚悚《犯罪現場》HD國粵雙語中字</a>, <a href="/html/gndy/dyzz/20191115/59398.html" class="ulink">2019年高分劇情《別告訴她》BD中英雙字幕</a>, <a href="/html/gndy/dyzz/20191114/59393.html" class="ulink">2019年動作《原始恐懼》BD中英雙字幕</a>, <a href="/html/gndy/dyzz/20191114/59392.html" class="ulink">2019年劇情《婚禮之后》BD中英雙字幕</a>, <a href="/html/gndy/dyzz/20191113/59387.html" class="ulink">2019年動作戰爭《危機:龍潭之戰》BD中英雙字幕</a>, <a href="/html/gndy/dyzz/20191113/59386.html" class="ulink">2019年犯罪動作《沉默的證人》BD國粵雙語中字</a>]

          詳情頁影片下載地址

          14:06:34.365 [pool-2-thread-1] INFO com.easy.webmagic.controller.MyPipeline - get page: https://www.dytt8.net/html/gndy/dyzz/20191204/59453.html
          14:06:34.365 [pool-2-thread-1] INFO com.easy.webmagic.controller.MyPipeline - download: <a href="ftp://ygdy8:ygdy8@yg45.dydytt.net:4233/陽光電影www.ygdy8.com.中國機長.HD.1080p.國語中英雙字.mkv">ftp://ygdy8:ygdy8@yg45.dydytt.net:4233/陽光電影www.ygdy8.com.中國機長.HD.1080p.國語中英雙字.mkv</a>

          表示成功抓取到數據,然后做你想做的事情了。

          爬蟲進階

          使用Selectable抽取元素

          Selectable相關的抽取元素鏈式API是WebMagic的一個核心功能。使用Selectable接口,你可以直接完成頁面元素的鏈式抽取,也無需去關心抽取的細節。

          爬蟲的配置、啟動和終止

          Spider是爬蟲啟動的入口。在啟動爬蟲之前,我們需要使用一個PageProcessor創建一個Spider對象,然后使用run()進行啟動。同時Spider的其他組件(Downloader、Scheduler、Pipeline)都可以通過set方法來進行設置。

          Jsoup和Xsoup

          WebMagic的抽取主要用到了Jsoup和我自己開發的工具Xsoup。

          爬蟲的監控

          利用這個功能,你可以查看爬蟲的執行情況——已經下載了多少頁面、還有多少頁面、啟動了多少線程等信息。該功能通過JMX實現,你可以使用Jconsole等JMX工具查看本地或者遠程的爬蟲信息。

          配置代理

          ProxyProvider有一個默認實現:SimpleProxyProvider。它是一個基于簡單Round-Robin的、沒有失敗檢查的ProxyProvider。可以配置任意個候選代理,每次會按順序挑選一個代理使用。它適合用在自己搭建的比較穩定的代理的場景。

          處理非HTTP GET請求

          采用在Request對象上添加Method和requestBody來實現。例如:

          Request request=new Request("http://xxx/path");
          request.setMethod(HttpConstant.Method.POST);
          request.setRequestBody(HttpRequestBody.json("{'id':1}","utf-8"));

          使用注解編寫爬蟲

          WebMagic支持使用獨有的注解風格編寫一個爬蟲,引入webmagic-extension包即可使用此功能。

          在注解模式下,使用一個簡單對象加上注解,可以用極少的代碼量就完成一個爬蟲的編寫。對于簡單的爬蟲,這樣寫既簡單又容易理解,并且管理起來也很方便。

          資料

          • https://github.com/smltq/spring-boot-demo

          談談網絡爬蟲

          1.1什么是網絡爬蟲

          在大數據時代,信息的采集是一項重要的工作,而互聯網中的數據是海量的,如果單純靠人力進行信息采集,不僅低效繁瑣,搜集的成本也會提高。如何自動高效地獲取互聯網中我們感興趣的信息并為我們所用是一個重要的問題,而爬蟲技術就是為了解決這些問題而生的。

          網絡爬蟲(Web crawler)也叫做網絡機器人,可以代替人們自動地在互聯網中進行數據信息的采集與整理。它是一種按照一定的規則,自動地抓取萬維網信息的程序或者腳

          本,可以自動采集所有其能夠訪問到的頁面內容,以獲取或更新這些網站的內容和檢索方式。

          從功能上來講,爬蟲一般分為數據采集,處理,儲存三個部分。爬蟲從一個或若干初始網頁的URL開始,獲得初始網頁上的URL,在抓取網頁的過程中,不斷從當前頁面上抽取新 的URL放入隊列,直到滿足系統的一定停止條件。

          1.2網絡爬蟲可以做什么

          我們初步認識了網絡爬蟲,網絡爬蟲具體可以做什么呢?

          可以實現搜索引擎

          大數據時代,可以讓我們獲取更多的數據源。

          快速填充測試和運營數據

          為人工智能提供訓練數據集

          1.3網絡爬蟲常用的技術(Java)

          1.3.1底層實現 HttpClient + Jsoup

          HttpClient 是 Apache Jakarta Common 下的子項目,用來提供高效的、最新的、功能豐富的支持 HTTP 協議的客戶端編程工具包,并且它支持 HTTP 協議最新的版本和建議。HttpClient 已經應用在很多的項目中,比如 Apache Jakarta 上很著名的另外兩個開源項目 Cactus 和 HTMLUnit 都使用了 HttpClient。更多信息請關注http://hc.apache.org/

          jsoup 是一款Java 的HTML解析器,可直接解析某個URL地址、HTML文本內容。它提供了一套非常省力的API,可通過DOM,CSS以及類似于jQuery的操作方法來取出和操作數 據。

          1.3.2開源框架 Webmagic

          webmagic是一個開源的Java爬蟲框架,目標是簡化爬蟲的開發流程,讓開發者專注于邏輯功能的開發。webmagic的核心非常簡單,但是覆蓋爬蟲的整個流程,也是很好的學習 爬蟲開發的材料。

          webmagic的主要特色:

          完全模塊化的設計,強大的可擴展性。

          核心簡單但是涵蓋爬蟲的全部流程,靈活而強大,也是學習爬蟲入門的好材料。提供豐富的抽取頁面API。

          無配置,但是可通過POJO+注解形式實現一個爬蟲。支持多線程。

          支持分布式。

          支持爬取js動態渲染的頁面。

          無框架依賴,可以靈活的嵌入到項目中去。

          2爬蟲框架Webmagic

          2.1架構解析

          WebMagic項目代碼分為核心和擴展兩部分。核心部分(webmagic-core)是一個精簡的、模塊化的爬蟲實現,而擴展部分則包括一些便利的、實用性的功能。擴展部分(webmagic-extension)提供一些便捷的功能,例如注解模式編寫爬蟲等。同時內置了一些常用的組件,便于爬蟲開發。

          WebMagic的設計目標是盡量的模塊化,并體現爬蟲的功能特點。這部分提供非常簡 單、靈活的API,在基本不改變開發模式的情況下,編寫一個爬蟲。

          WebMagic的結構分為Downloader、PageProcessor、Scheduler、Pipeline四大組 件,并由Spider將它們彼此組織起來。這四大組件對應爬蟲生命周期中的下載、處理、管 理和持久化等功能。而Spider則將這幾個組件組織起來,讓它們可以互相交互,流程化的 執行,可以認為Spider是一個大的容器,它也是WebMagic邏輯的核心。

          四大組件

          Downloader

          Downloader負責從互聯網上下載頁面,以便后續處理。WebMagic默認使用了ApacheHttpClient作為下載工具。

          PageProcessor

          PageProcessor負責解析頁面,抽取有用信息,以及發現新的鏈接。WebMagic使用Jsoup

          作為HTML解析工具,并基于其開發了解析XPath的工具Xsoup。

          在這四個組件中,PageProcessor對于每個站點每個頁面都不一樣,是需要使用者定制的部分。

          Scheduler

          Scheduler負責管理待抓取的URL,以及一些去重的工作。WebMagic默認提供了JDK的內存隊列來管理URL,并用集合來進行去重。也支持使用Redis進行分布式管理。

          Pipeline

          Pipeline負責抽取結果的處理,包括計算、持久化到文件、數據庫等。WebMagic默認提供了“輸出到控制臺”和“保存到文件”兩種結果處理方案。

          2.2PageProcessor

          需求:編寫爬蟲程序,爬取csdn中博客–工人智能的內容

          2.2.1爬取頁面全部內容

          https://blog.csdn.net/nav/ai

          (1)創建工程,引入依賴

          <dependency>
          <groupId>us.codecraft</groupId>
          <artifactId>webmagic‐core</artifactId>
          <version>0.7.3</version>
          </dependency>
          <dependency>
          <groupId>us.codecraft</groupId>
          <artifactId>webmagic‐extension</artifactId>
          <version>0.7.3</version>
          </dependency>
          

          (2)編寫類實現網頁內容的爬取

          package cn.itcast.demo;
          import us.codecraft.webmagic.Page; import us.codecraft.webmagic.Site; import us.codecraft.webmagic.Spider;
          import us.codecraft.webmagic.processor.PageProcessor;
          /**
          * 爬取類
          */
          public class MyProcessor implements PageProcessor {
          public void process(Page page) {
          System.out.println(page.getHtml().toString());
          }
          public Site getSite() {
          return Site.me().setSleepTime(100).setRetryTimes(3);
          }
          public static void main(String[] args) {
          Spider.create( new MyProcessor()
          ).addUrl("https://blog.csdn.net").run();
          }
          }
          

          Spider是爬蟲啟動的入口。在啟動爬蟲之前,我們需要使用一個PageProcessor創建一個Spider對象,然后使用run()進行啟動。

          同時Spider的其他組件(Downloader、Scheduler、Pipeline)都可以通過set方法來 進行設置。

          Page代表了從Downloader下載到的一個頁面——可能是HTML,也可能是JSON或者其他文本格式的內容。Page是WebMagic抽取過程的核心對象,它提供一些方法可供抽 取、結果保存等。

          Site用于定義站點本身的一些配置信息,例如編碼、HTTP頭、超時時間、重試策略 等、代理等,都可以通過設置Site對象來進行配置。

          2.2.2爬取指定內容(XPath)

          如果我們想爬取網頁中部分的內容,需要指定xpath。

          XPath,即為XML路徑語言(XMLPathLanguage),它是一種用來確定XML文檔中某 部分位置的語言。XPath 使用路徑表達式來選取 XML 文檔中的節點或者節點集。這些路徑表達式和我們在常規的電腦文件系統中看到的表達式非常相似。 語法詳見附錄A

          我們通過指定xpath來抓取網頁的部分內容

          System.out.println(page.getHtml().xpath("http://* [@id=\"nav\"]/div/div/ul/li[5]/a").toString());
          

          以上代碼的含義:id為nav的節點下的div節點下的div節點下的ul下的第5個li節點下的a節點看一下輸出結果

          <a href="/nav/ai">人工智能</a>
          

          2.2.3添加目標地址

          我們可以通過添加目標地址,從種子頁面爬取到更多的頁面

          public void process(Page page) {
          page.addTargetRequests( page.getHtml().links().all() );//將當前頁面里的所有鏈接都添加到目標頁面中
          System.out.println(page.getHtml().xpath("http://* [@id=\"nav\"]/div/div/ul/li[5]/a").toString());
          }
          

          運行后發現好多地址都出現在控制臺

          2.2.4目標地址正則匹配

          需求:只提取播客的文章詳細頁內容,并提取標題

          package cn.itcast.demo;
          import us.codecraft.webmagic.Page; import us.codecraft.webmagic.Site; import us.codecraft.webmagic.Spider;
          import us.codecraft.webmagic.processor.PageProcessor;
          /**
          * 爬取類
          */
          public class MyProcessor implements PageProcessor {
          public void process(Page page) {
          //page.addTargetRequests( page.getHtml().links().all() );//將當前頁面里的所有鏈接都添加到目標頁面中
          // page.addTargetRequests(
          page.getHtml().links().regex("https://blog.csdn.net/[a‐z 0‐9
          ‐]+/article/details/[0‐9]{8}").all() );
          System.out.println(page.getHtml().xpath("http://* [@id=\"mainBox\"]/main/div[1]/div[1]/h1/text()").toString());
          }
          public Site getSite() {
          return Site.me().setSleepTime(100).setRetryTimes(3);
          }
          public static void main(String[] args) { Spider.create( new MyProcessor()
          ).addUrl("https://blog.csdn.net/nav/ai").run();
          }
          }
          

          2.3Pipeline

          2.3.1ConsolePipeline 控制臺輸出

          /**
          * 爬取類
          */
          public class MyProcessor implements PageProcessor {
          public void process(Page page) {
          //page.addTargetRequests( page.getHtml().links().all() );//將當前頁面里的所有鏈接都添加到目標頁面中
          // page.addTargetRequests(
          page.getHtml().links().regex("https://blog.csdn.net/[a‐z 0‐9
          ‐]+/article/details/[0‐9]{8}").all() );
          //System.out.println(page.getHtml().xpath("http://* [@id=\"mainBox\"]/main/div[1]/div[1]/h1/text()").toString());
          page.putField("title",page.getHtml().xpath("http://* [@id=\"mainBox\"]/main/div[1]/div[1]/h1/text()").toString());
          }
          public Site getSite() {
          return Site.me().setSleepTime(100).setRetryTimes(3);
          }
          public static void main(String[] args) { Spider.create( new MyProcessor() )
          .addUrl("https://blog.csdn.net")
          .addPipeline(new ConsolePipeline())
          .run();
          }
          }
          

          2.3.2FilePipeline 文件保存

          public static void main(String[] args) { Spider.create( new MyProcessor() )
          .addUrl("https://blog.csdn.net")
          .addPipeline(new ConsolePipeline())
          .addPipeline(new FilePipeline("e:/data"))//以文件方式保存
          .run();
          }
          

          2.3.3JsonFilePipeline

          以json方式保存

          public static void main(String[] args) {
          Spider.create( new MyProcessor() )
          .addUrl("https://blog.csdn.net")
          .addPipeline(new ConsolePipeline())
          .addPipeline(new FilePipeline("e:/data"))
          .addPipeline(new JsonFilePipeline("e:/json"))// 以json方式保存
          .run();
          }
          

          2.3.4定制Pipeline

          如果以上Pipeline都不能滿足你的需要,你可以定制Pipeline

          (1)創建類MyPipeline實現接口Pipeline

          package cn.itcast.demo;
          import us.codecraft.webmagic.ResultItems;
          import us.codecraft.webmagic.Task;
          import us.codecraft.webmagic.pipeline.Pipeline;
          public class MyPipeline implements Pipeline {
          public void process(ResultItems resultItems, Task task) {
          String title=resultItems.get("title"); System.out.println("我的定制的 title:"+title);
          }
          }
          

          (2)修改main方法

          public static void main(String[] args) { Spider.create( new MyProcessor() )
          .addUrl("https://blog.csdn.net")
          .addPipeline(new ConsolePipeline())
          .addPipeline(new FilePipeline("e:/data"))
          .addPipeline(new JsonFilePipeline("e:/json"))
          .addPipeline(new MyPipeline())//定制化輸出
          .run();
          }
          

          2.4Scheduler

          我們剛才完成的功能,每次運行可能會爬取重復的頁面,這樣做是沒有任何意義的。Scheduler(URL管理) 最基本的功能是實現對已經爬取的URL進行標示??梢詫崿FURL的增量去重。

          目前scheduler主要有三種實現方式:

          1)內存隊列 QueueScheduler

          2)文件隊列FileCacheQueueScheduler

          3) Redis隊列 RedisScheduler

          2.4.1內存隊列

          使用setScheduler來設置Scheduler

          public static void main(String[] args) { Spider.create( new MyProcessor() )
          .addUrl("https://blog.csdn.net")
          .setScheduler(new QueueScheduler())
          .run();
          }
          

          2.4.2文件隊列

          使用文件保存抓取URL,可以在關閉程序并下次啟動時,從之前抓取到的URL繼續抓取

          (1)創建文件夾E:\scheduler

          (2)修改代碼

          public static void main(String[] args) { Spider.create( new MyProcessor() )
          .addUrl("https://blog.csdn.net")
          //.setScheduler(new QueueScheduler())//設置內存隊列
          .setScheduler(new FileCacheQueueScheduler("E:\\scheduler"))//設置文件隊列
          .run();
          }
          

          運行后文件夾E:\scheduler會產生兩個文件blog.csdn.net.urls.txt和

          blog.csdn.net.cursor.txt

          2.4.3Redis隊列

          使用Redis保存抓取隊列,可進行多臺機器同時合作抓取

          (1)運行redis服務端

          (2)修改代碼

          public static void main(String[] args) { Spider.create( new MyProcessor() )
          .addUrl("https://blog.csdn.net")
          //.setScheduler(new QueueScheduler())//設置內存隊列
          //.setScheduler(new FileCacheQueueScheduler("E:\\scheduler"))//設置文件隊列
          .setScheduler(new RedisScheduler("127.0.0.1"))//設置Redis隊
          列
          .run();
          }
          

          3十次方文章爬取

          3.1需求分析

          每日某時間段整從CSDN播客中爬取文檔,存入文章數據庫中。

          3.2頻道設置

          向數據庫tensquare_article的tb_channel表中添加記錄

          3.3代碼編寫

          3.3.1模塊搭建

          (1)創建模塊tensquare_article_crawler ,引入依賴

          <dependency>
          <groupId>us.codecraft</groupId>
          <artifactId>webmagic‐core</artifactId>
          <version>0.7.3</version>
          <exclusions>
          <exclusion>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j‐log4j12</artifactId>
          </exclusion>
          </exclusions>
          </dependency>
          <dependency>
          <groupId>us.codecraft</groupId>
          <artifactId>webmagic‐extension</artifactId>
          <version>0.7.3</version>
          </dependency>
          <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring‐boot‐starter‐data‐jpa</artifactId>
          </dependency>
          <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql‐connector‐java</artifactId>
          </dependency>
          <dependency>
          <groupId>com.tensquare</groupId>
          <artifactId>tensquare_common</artifactId>
          <version>1.0‐SNAPSHOT</version>
          </dependency>
          

          (2)創建配置文件application.yml

          server: port: 9014
          spring: application:
          name: tensquare‐crawler #指定服務名
          datasource:
          driverClassName: com.mysql.jdbc.Driver
          url: jdbc:mysql://127.0.0.1:3306/tensquare_article? characterEncoding=UTF8
          username: root password: 123456
          jpa:
          database: MySQL show‐sql: true
          redis:
          host: 127.0.0.1
          

          (3)創建啟動類

          @SpringBootApplication
          @EnableScheduling
          public class CrawlerApplication {
          @Value("${redis.host}")
          private String redis_host;
          public static void main(String[] args) {
          SpringApplication.run(CrawlerApplication.class, args);
          }
          @Bean
          public IdWorker idWorkker(){ return new IdWorker(1, 1);
          }
          @Bean
          public RedisScheduler redisScheduler(){ return new RedisScheduler(redis_host);
          }
          }
          

          (4)實體類及數據訪問接口參見文章微服務。代碼略

          3.3.2爬取類

          創建文章爬取類ArticleProcessor

          package com.tensquare.crawler.processor; import us.codecraft.webmagic.Page; import us.codecraft.webmagic.Site;
          import us.codecraft.webmagic.processor.PageProcessor;
          /**
          * 文章爬取類
          */ @Component
          public class ArticleProcessor implements PageProcessor {
          @Override
          public void process(Page page) {
          page.addTargetRequests(page.getHtml().links().regex("https://blog.csdn.net/ [a‐z 0‐9 ‐]+/article/details/[0‐9]{8}").all());
          String title=page.getHtml().xpath("http://* [@id=\"mainBox\"]/main/div[1]/div[1]/h1/text()").get();
          String content=page.getHtml().xpath("http://* [@id=\"article_content\"]/div/div[1]").get();
          //獲取頁面需要的內容System.out.println("標題:"+title ); System.out.println("內容:"+content );
          if(title!=null && content!=null){	//如果有標題和內容page.putField("title",title); page.putField("content",content);
          }else{
          page.setSkip(true);//跳過
          }
          }
          @Override
          public Site getSite() {
          return Site.me().setRetryTimes(3000).setSleepTime(100);
          }
          }
          

          3.3.3入庫類

          創建文章入庫類ArticleDbPipeline ,負責將爬取的數據存入數據庫

          package com.tensquare.crawler.pipeline;
           import com.tensquare.crawler.dao.ArticleDao;
           import com.tensquare.crawler.pojo.Article;
          import org.springframework.beans.factory.annotation.Autowired; 
          import org.springframework.stereotype.Repository;
          import us.codecraft.webmagic.ResultItems; 
          import us.codecraft.webmagic.Task;
          import us.codecraft.webmagic.pipeline.Pipeline;
           import util.IdWorker;
          import java.util.Map;
          /**
          * 入庫類
          */ @Component
          public class ArticleDbPipeline implements Pipeline {
          @Autowired
          private ArticleDao articleDao;
          @Autowired
          private IdWorker idWorker;
          public void setChannelId(String channelId) { 
          this.channelId=channelId;
          }
          private String channelId;//頻道ID @Override
          public void process(ResultItems resultItems, Task task) { 
          String title=resultItems.get("title");
          String content=resultItems.get("content"); 
          Article article=new Article(); article.setId(idWorker.nextId()+""); 
          article.setChannelid(channelId); article.setTitle(title);
           article.setContent(content);
           articleDao.save(article);
          }
          }
          

          ReusltItems相當于一個Map,它保存PageProcessor處理的結果,供Pipeline使用。它的API與Map很類似,值得注意的是它有一個字段skip,若設置為true,則不應被Pipeline處理。

          3.3.4任務類

          創建任務類

          package com.tensquare.crawler.task;
          import com.tensquare.crawler.pipeline.ArticleDbPipeline;
           import com.tensquare.crawler.pipeline.ArticleTxtPipeline;
           import com.tensquare.crawler.processor.ArticleProcessor;
           import org.springframework.beans.factory.annotation.Autowired;
           import org.springframework.scheduling.annotation.Scheduled; 
           import org.springframework.stereotype.Component;
          import us.codecraft.webmagic.Spider;
          import us.codecraft.webmagic.scheduler.RedisScheduler;
          /**
          * 文章任務類
          */ @Component
          public class ArticleTask {
          @Autowired
          private ArticleDbPipeline articleDbPipeline;
          @Autowired
          private ArticleTxtPipeline articleTxtPipeline;
          @Autowired
          private RedisScheduler redisScheduler;
          @Autowired
          private ArticleProcessor articleProcessor;
          /**
          * 爬取ai數據
          */
          @Scheduled(cron="0 54 21 * * ?") public void aiTask(){
          System.out.println("爬取AI文章");
          Spider spider=Spider.create(articleProcessor); spider.addUrl("https://blog.csdn.net/nav/ai"); articleTxtPipeline.setChannelId("ai"); articleDbPipeline.setChannelId("ai"); spider.addPipeline(articleDbPipeline); spider.addPipeline(articleTxtPipeline); spider.setScheduler(redisScheduler);
          spider.start();
          }
          /**
          * 爬取db數據
          */
          @Scheduled(cron="20 17 11 * * ?") public void dbTask(){
          System.out.println("爬取DB文章");
          Spider spider=Spider.create(articleProcessor); spider.addUrl("https://blog.csdn.net/nav/db"); articleTxtPipeline.setChannelId("db"); spider.addPipeline(articleTxtPipeline); spider.setScheduler(redisScheduler); spider.start();
          }
          /**
          * 爬取web數據
          */
          @Scheduled(cron="20 27 11 * * ?") public void webTask(){
          System.out.println("爬取WEB文章");
          Spider spider=Spider.create(articleProcessor); spider.addUrl("https://blog.csdn.net/nav/web"); articleTxtPipeline.setChannelId("web"); spider.addPipeline(articleTxtPipeline); spider.setScheduler(redisScheduler); spider.start();
          }
          }
          

          4十次方用戶數據爬取

          4.1需求分析

          從csdn中爬取用戶昵稱和頭像,存到用戶表,頭像圖片存儲到本地

          4.2代碼編寫

          4.2.1模塊搭建

          (1)創建工程tensquare_user_crawler。pom.xml引入依賴

          <dependency>

          <groupId>us.codecraft</groupId>

          <artifactId>webmagic‐core</artifactId>

          <version>0.7.3</version>

          <exclusions>

          <exclusion>

          <groupId>org.slf4j</groupId>

          <artifactId>slf4j‐log4j12</artifactId>

          </exclusion>

          </exclusions>

          </dependency>

          <dependency>

          <groupId>us.codecraft</groupId>

          <artifactId>webmagic‐extension</artifactId>

          <version>0.7.3</version>

          </dependency>

          <dependency>

          <groupId>org.springframework.boot</groupId>

          <artifactId>spring‐boot‐starter‐data‐jpa</artifactId>

          </dependency>

          <dependency>

          <groupId>mysql</groupId>

          <artifactId>mysql‐connector‐java</artifactId>

          </dependency>

          <dependency>

          <groupId>com.tensquare</groupId>

          <artifactId>tensquare_common</artifactId>

          <version>1.0‐SNAPSHOT</version>

          </dependency>

          (2)創建配置文件application.yml

          server: port: 9015
          spring: application:
          name: tensquare‐user‐crawler #指定服務名
          datasource:
          driverClassName: com.mysql.jdbc.Driver
          url: jdbc:mysql://127.0.0.1:3306/tensquare_user?characterEncoding=UTF8 username: root
          password: 123456 jpa:
          database: MySQL show‐sql: true
          redis:
          host: 127.0.0.1
          

          (3)創建啟動類

          @SpringBootApplication
          @EnableScheduling
          public class UserCrawlerApplication {
          @Value("${redis.host}")
          private String redis_host;
          public static void main(String[] args) {
          SpringApplication.run(CrawlerApplication.class, args);
          }
          @Bean
          public IdWorker idWorkker(){ return new IdWorker(1, 1);
          }
          @Bean
          public RedisScheduler redisScheduler(){ return new RedisScheduler(redis_host);
          }
          }
          

          (4)實體類及數據訪問接口

          參見用戶微服務。代碼略

          4.2.2爬取類

          package com.tensquare.usercrawler.processor;
           import org.springframework.stereotype.Component;
           import us.codecraft.webmagic.Page;
          import us.codecraft.webmagic.Site;
          import us.codecraft.webmagic.processor.PageProcessor;
          /**
          * 文章爬取類
          */ @Component
          public class UserProcessor implements PageProcessor {
          @Override
          public void process(Page page) {
          page.addTargetRequests(page.getHtml().links().regex("https://blog.csdn.net/ [a‐z 0‐9 ‐]+/article/details/[0‐9]{8}").all());
          String nickname=page.getHtml().xpath("http://* [@id=\"uid\"]/text()").get();
          String image=page.getHtml().xpath("http://* [@id=\"asideProfile\"]/div[1]/div[1]/a").css("img","src").toString();
          if(nickname!=null && image!=null){	//如果有昵稱和頭像
          page.putField("nickname",nickname); page.putField("image",image);
          }else{
          page.setSkip(true);//跳過
          }
          }
          @Override
          public Site getSite() {
          return Site.me().setRetryTimes(3000).setSleepTime(100);
          }
          }
          

          4.2.3下載工具類

          資源提供了工具類,拷貝至tensquare_common工程的util包下

          package util; import java.io.*; import java.net.URL;
          import java.net.URLConnection;
          /**
          * 下載工具類
          */
          public class DownloadUtil {
          public static void download(String urlStr,String filename,String savePath) throws IOException {
          URL url=new URL(urlStr);
          //打開url連接
          URLConnection connection=url.openConnection();
          //請求超時時間connection.setConnectTimeout(5000);
          //輸入流
          InputStream in=connection.getInputStream();
          //緩沖數據
          byte [] bytes=new byte[1024];
          //數據長度int len;
          //文件
          File file=new File(savePath); if(!file.exists())
          file.mkdirs(); OutputStream out=new
          FileOutputStream(file.getPath()+"\\"+filename);
          //先讀到bytes中
          while ((len=in.read(bytes))!=‐1){
          //再從bytes中寫入文件out.write(bytes,0,len);
          }
          // 關 閉 IO out.close();
          in.close();
          }
          }
          

          4.2.4入庫類

          package com.tensquare.usercrawler.pipeline; 
          import com.tensquare.usercrawler.dao.UserDao; 
          import com.tensquare.usercrawler.pojo.User;
          import org.springframework.beans.factory.annotation.Autowired; 
          import org.springframework.stereotype.Component;
          import us.codecraft.webmagic.ResultItems; 
          import us.codecraft.webmagic.Task;
          import us.codecraft.webmagic.pipeline.Pipeline;
           import util.DownloadUtil;
          import util.IdWorker; import java.io.IOException; 
          @Component
          public class UserPipeline implements Pipeline {
          @Autowired
          private IdWorker idWorker;
          @Autowired
          private UserDao userDao;
          @Override
          public void process(ResultItems resultItems, Task task) {
          User user=new User(); user.setId(idWorker.nextId()+""); 
          user.setNickname(resultItems.get("nickname"));
           String image=resultItems.get("image");//圖片地址
          String fileName=image.substring(image.lastIndexOf("/")+1); 
          user.setAvatar(fileName);
          userDao.save(user);
          //下載圖片try {
          DownloadUtil.download(image,fileName,"e:/userimg");
          } catch (IOException e) { e.printStackTrace();
          }
          }
          }
          

          4.2.5任務類

          package com.tensquare.usercrawler.task;
          import com.tensquare.usercrawler.pipeline.UserPipeline;
           import com.tensquare.usercrawler.processor.UserProcessor;
           import org.springframework.beans.factory.annotation.Autowired;
           import org.springframework.scheduling.annotation.Scheduled; 
           import org.springframework.stereotype.Component;
          import us.codecraft.webmagic.Spider;
          import us.codecraft.webmagic.scheduler.RedisScheduler;
          /**
          * 用戶爬取任務類
          */ @Component
          public class UserTask {
          @Autowired
          private RedisScheduler redisScheduler;
          @Autowired
          private UserPipeline userPipeline;
          @Autowired
          private UserProcessor userProcessor;
          /**
          * 爬取用戶數據
          */
          @Scheduled(cron="0 56 22 * * ?") 
          public void userTask(){
          System.out.println("爬取用戶");
          Spider spider=Spider.create(userProcessor); 
          spider.addUrl("https://blog.csdn.net"); 
          spider.addPipeline(userPipeline); 
          spider.setScheduler(redisScheduler); spider.start();
          }
          }
          

          附錄 A XPath語法

          (1)選取節點:

          (2)謂語

          謂語用來查找某個特定的節點或者包含某個指定的值的節點。謂語被嵌在方括號中

          (3)通配符

          XPath 通配符可用來選取未知的 XML 元素,通配指定節點。

          (4)多路徑選擇

          通過在路徑表達式中使用“|”運算符,您可以選取若干個路徑。**

          (5)XPath 軸

          軸可定義相對于當前節點的節點集。

          (6)XPath 運算符

          (7)常用的功能函數

          使用功能函數能夠更好的進行模糊搜索

          >這段代碼的分為兩部分,page.getHtml().links().regex("(https://github\\.com/\\w+/\\w+)").all()用于獲取所有滿足"(https:/ /github\.com/\w+/\w+)"這個正則表達式的鏈接,page.addTargetRequests()則將這些鏈接加入到待抓取的隊列中去。

          主站蜘蛛池模板: 国产精品日韩欧美一区二区三区| 91视频国产一区| 久久精品无码一区二区app| 国产成人无码aa精品一区| 无码午夜人妻一区二区三区不卡视频| 亚洲国产欧美国产综合一区 | 在线精品一区二区三区电影| 蜜芽亚洲av无码一区二区三区| 一区二区三区免费在线视频 | 香蕉视频一区二区三区| 色噜噜狠狠一区二区| 国产av福利一区二区三巨| 国产微拍精品一区二区| 亚洲视频一区二区在线观看| 久久精品国产第一区二区| 在线成人综合色一区| 无码aⅴ精品一区二区三区浪潮| 成人毛片无码一区二区| 精品福利一区二区三区免费视频| 一区视频免费观看| 无码少妇一区二区浪潮av| 精品日韩一区二区三区视频| 国产日韩一区二区三区在线播放 | 精品一区二区三区四区在线| 午夜DV内射一区区| 国产SUV精品一区二区四| 2021国产精品视频一区| 麻豆高清免费国产一区| 亚洲欧洲精品一区二区三区| 日韩精品无码一区二区中文字幕| 亚洲日韩精品一区二区三区| 国产一区二区精品尤物| 中文字幕一区二区三区永久| 成人区精品一区二区不卡| 亚洲国产综合精品一区在线播放| 婷婷国产成人精品一区二| 日本道免费精品一区二区| 日韩免费无码视频一区二区三区| 精品乱码一区二区三区四区| 亚洲AV无码一区二区大桥未久 | 国产微拍精品一区二区|