整合營銷服務商

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

          免費咨詢熱線:

          爬蟲系列(1):抓取網頁URL

          上一節(爬蟲系列(0):項目搭建)

          網絡爬蟲的都是通過多線程,多任務邏輯實現的,在springboot框架中已封裝線程池(ThreadPoolTaskExecutor),我們只需要使用就是了。

          這一節我們主要實現多線程抓取網頁連接信息,并將信息存儲在隊列里面。

          引入新包

          在pom中引入新包,具體如下:

           <dependency>
                  <!-- common工具包 -->
          		<groupId>org.apache.commons</groupId>
          		<artifactId>commons-lang3</artifactId>
          	</dependency>
          	<dependency>
          	    <!-- java處理HTML的工具包 -->
          		<groupId>org.jsoup</groupId>
          		<artifactId>jsoup</artifactId>
          		<version>1.8.3</version>
          	</dependency>
          	<dependency>
          	    <!-- lombok工具包,簡化編碼 -->
          		<groupId>org.projectlombok</groupId>
          		<artifactId>lombok</artifactId>
          		<scope>provided</scope>
          	</dependency>

          為了簡化編碼,這里引入了lombok,在使用時候IDE需要安裝lombok插件,否則會提示編譯錯誤。

          配置管理

          springboot的配置文件都是在application.properties(.yml)統一管理的,在這里,我們也把爬蟲相關的配置通過@ConfigurationProperties注解來實現。直接上代碼:

          package mobi.huanyuan.spider.config;
          
          import lombok.Data;
          import org.springframework.boot.context.properties.ConfigurationProperties;
          
          /**
           * 爬蟲配置.
           *
           * @author Jonathan L.(xingbing.lai@gmail.com)
           * @version 1.0.0 -- Datetime: 2020/2/18 11:10
           */
          @Data
          @ConfigurationProperties(prefix = "huanyuan.spider")
          public class SpiderConfig {
              /**
               * 爬取頁面最大深度
               */
              public int maxDepth = 2;
              
              /**
               * 下載頁面線程數
               */
              public int minerHtmlThreadNum = 2;
          
              //=================================================
              //  線程池配置
              //=================================================
              /**
               * 核心線程池大小
               */
              private int corePoolSize = 4;
          
              /**
               * 最大可創建的線程數
               */
              private int maxPoolSize = 100;
          
              /**
               * 隊列最大長度
                */
              private int queueCapacity = 1000;
          
              /**
               * 線程池維護線程所允許的空閑時間
               */
              private int keepAliveSeconds = 300;
          }

          然后,需要修改這些配置,只需要修改application.properties(.yml)里邊即可:


          幻猿簡易爬蟲配置


          線程池

          線程池使用springboot已有的,配置也在上邊配置管理里邊有,這里只初始化配置即可:

          package mobi.huanyuan.spider.config;
          
          import org.springframework.beans.factory.annotation.Autowired;
          import org.springframework.context.annotation.Bean;
          import org.springframework.context.annotation.Configuration;
          import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
          
          import java.util.concurrent.ThreadPoolExecutor;
          
          /**
           * 線程池配置.
           *
           * @author Jonathan L.(xingbing.lai@gmail.com)
           * @version 1.0.0 -- Datetime: 2020/2/18 11:35
           */
          @Configuration
          public class ThreadPoolConfig {
              @Autowired
              private SpiderConfig spiderConfig;
          
              @Bean(name = "threadPoolTaskExecutor")
              public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
                  ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
                  executor.setMaxPoolSize(spiderConfig.getMaxPoolSize());
                  executor.setCorePoolSize(spiderConfig.getCorePoolSize());
                  executor.setQueueCapacity(spiderConfig.getQueueCapacity());
                  executor.setKeepAliveSeconds(spiderConfig.getKeepAliveSeconds());
                  // 線程池對拒絕任務(無線程可用)的處理策略
                  executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
                  return executor;
              }
          
          }

          隊列管理

          這一節我們主要是抓取URL并保存進隊列,所以涉及到的隊列有待抓取隊列和待分析隊列(下一節分析時候用,這里只做存儲),此外,為了防止重復抓取同一個URL,這里還需要加一個Set集合,將已訪問過的地址做個記錄。

          package mobi.huanyuan.spider;
          
          import lombok.Getter;
          import mobi.huanyuan.spider.bean.SpiderHtml;
          import org.slf4j.Logger;
          import org.slf4j.LoggerFactory;
          
          import java.util.HashSet;
          import java.util.LinkedList;
          import java.util.Queue;
          import java.util.Set;
          
          /**
           * 爬蟲訪問隊列.
           *
           * @author Jonathan L.(xingbing.lai@gmail.com)
           * @version 1.0.0 -- Datetime: 2020/2/18 10:54
           */
          public class SpiderQueue {
              private static Logger logger = LoggerFactory.getLogger(SpiderQueue.class);
          
              /**
               * Set集合 保證每一個URL只訪問一次
               */
              private static volatile Set<String> urlSet = new HashSet<>();
              /**
               * 待訪問隊列<br>
               * 爬取頁面線程從這里取數據
               */
              private static volatile Queue<SpiderHtml> unVisited = new LinkedList<>();
          
              /**
               * 等待提取URL的分析頁面隊列<br>
               * 解析頁面線程從這里取數據
               */
              private static volatile Queue<SpiderHtml> waitingMine = new LinkedList<>();
          
              /**
               * 添加到URL隊列
               *
               * @param url
               */
              public synchronized static void addUrlSet(String url) {
                  urlSet.add(url);
              }
          
              /**
               * 獲得URL隊列大小
               *
               * @return
               */
              public static int getUrlSetSize() {
                  return urlSet.size();
              }
          
              /**
               * 添加到待訪問隊列,每個URL只訪問一次
               *
               * @param spiderHtml
               */
              public synchronized static void addUnVisited(SpiderHtml spiderHtml) {
                  if (null != spiderHtml && !urlSet.contains(spiderHtml.getUrl())) {
                      logger.info("添加到待訪問隊列[{}] 當前第[{}]層 當前線程[{}]", spiderHtml.getUrl(), spiderHtml.getDepth(), Thread.currentThread().getName());
                      unVisited.add(spiderHtml);
                  }
              }
          
              /**
               * 待訪問出隊列
               *
               * @return
               */
              public synchronized static SpiderHtml unVisitedPoll() {
                  return unVisited.poll();
              }
          
              /**
               * 添加到等待提取URL的分析頁面隊列
               *
               * @param html
               */
              public synchronized static void addWaitingMine(SpiderHtml html) {
                  waitingMine.add(html);
              }
          
              /**
               * 等待提取URL的分析頁面出隊列
               *
               * @return
               */
              public synchronized static SpiderHtml waitingMinePoll() {
                  return waitingMine.poll();
              }
          
              /**
               * 等待提取URL的分析頁面隊列大小
               * @return
               */
              public static int waitingMineSize() {
                  return waitingMine.size();
              }
          }

          抓取任務

          直接上代碼:

          package mobi.huanyuan.spider.runable;
          
          import mobi.huanyuan.spider.SpiderQueue;
          import mobi.huanyuan.spider.bean.SpiderHtml;
          import mobi.huanyuan.spider.config.SpiderConfig;
          import org.apache.commons.lang3.StringUtils;
          import org.jsoup.Connection;
          import org.jsoup.Jsoup;
          import org.jsoup.nodes.Document;
          import org.slf4j.Logger;
          import org.slf4j.LoggerFactory;
          
          /**
           * 抓取頁面任務.
           *
           * @author Jonathan L.(xingbing.lai@gmail.com)
           * @version 1.0.0 -- Datetime: 2020/2/18 11:43
           */
          public class SpiderHtmlRunnable implements Runnable {
              private static final Logger logger = LoggerFactory.getLogger(SpiderHtmlRunnable.class);
              private static boolean done = false;
              private SpiderConfig config;
          
              public SpiderHtmlRunnable(SpiderConfig config) {
                  this.config = config;
              }
          
              @Override
              public void run() {
                  while (!SpiderHtmlRunnable.done) {
                      done = true;
                      minerHtml();
                      done = false;
                  }
              }
          
              public synchronized void minerHtml() {
                  SpiderHtml minerUrl = SpiderQueue.unVisitedPoll(); // 待訪問出隊列。
                  try {
                      //判斷當前頁面爬取深度
                      if (null == minerUrl || StringUtils.isBlank(minerUrl.getUrl()) || minerUrl.getDepth() > config.getMaxDepth()) {
                          return;
                      }
                      //判斷爬取頁面URL是否包含http
                      if (!minerUrl.getUrl().startsWith("http")) {
                          logger.info("當前爬取URL[{}]沒有http", minerUrl.getUrl());
                          return;
                      }
                      logger.info("當前爬取頁面[{}]爬取深度[{}] 當前線程 [{}]", minerUrl.getUrl(), minerUrl.getDepth(), Thread.currentThread().getName());
                      Connection conn = Jsoup.connect(minerUrl.getUrl());
                      conn.header("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.27 Safari/525.13");//配置模擬瀏覽器
                      Document doc = conn.get();
                      String page = doc.html();
          
                      SpiderHtml spiderHtml = new SpiderHtml();
                      spiderHtml.setUrl(minerUrl.getUrl());
                      spiderHtml.setHtml(page);
                      spiderHtml.setDepth(minerUrl.getDepth());
          
                      System.out.println(spiderHtml.getUrl());
                      // TODO: 添加到繼續爬取隊列
                      SpiderQueue.addWaitingMine(spiderHtml);
                  } catch (Exception e) {
                      logger.info("爬取頁面失敗 URL [{}]", minerUrl.getUrl());
                      logger.info("Error info [{}]", e.getMessage());
                  }
          
              }
          }

          這里就是個Runnable任務,主要目標就是拉去URL數據,然后封裝成SpiderHtml對象存放在待分析隊列里邊。 這里用到了jsoup--一個java對HTML分析操作的工具包,不清楚的可以去搜索看看,之后章節涉及到分析的部分也會用到。

          其他

          頁面信息封裝類SpiderHtml

          package mobi.huanyuan.spider.bean;
          
          import lombok.Data;
          
          import java.io.Serializable;
          
          /**
           * 頁面信息類.
           *
           * @author Jonathan L.(xingbing.lai@gmail.com)
           * @version 1.0.0 -- Datetime: 2020/2/18 11:02
           */
          @Data
          public class SpiderHtml implements Serializable {
              /**
               * 頁面URL
               */
              private String url;
              /**
               * 頁面信息
               */
              private String html;
              /**
               * 爬取深度
               */
              private int depth;
          }

          爬蟲主類

          package mobi.huanyuan.spider;
          
          import mobi.huanyuan.spider.bean.SpiderHtml;
          import mobi.huanyuan.spider.config.SpiderConfig;
          import mobi.huanyuan.spider.runable.SpiderHtmlRunnable;
          import org.slf4j.Logger;
          import org.slf4j.LoggerFactory;
          import org.springframework.beans.factory.annotation.Autowired;
          import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
          import org.springframework.stereotype.Component;
          
          import java.util.concurrent.TimeUnit;
          
          /**
           * 爬蟲.
           *
           * @author Jonathan L.(xingbing.lai@gmail.com)
           * @version 1.0.0 -- Datetime: 2020/2/18 11:23
           */
          @Component
          public class Spider {
              private static Logger logger = LoggerFactory.getLogger(Spider.class);
          
              @Autowired
              private ThreadPoolTaskExecutor threadPoolTaskExecutor;
              @Autowired
              private SpiderConfig spiderConfig;
          
              public void start(SpiderHtml spiderHtml) {
          
                  //程序啟動,將第一個起始頁面放入待訪問隊列。
                  SpiderQueue.addUnVisited(spiderHtml);
                  //將URL 添加到URL隊列 保證每個URL只訪問一次
                  SpiderQueue.addUrlSet(spiderHtml.getUrl());
          
                  //download
                  for (int i = 0; i < spiderConfig.getMinerHtmlThreadNum(); i++) {
                      SpiderHtmlRunnable minerHtml = new SpiderHtmlRunnable(spiderConfig);
                      threadPoolTaskExecutor.execute(minerHtml);
                  }
                  // TODO: 監控爬取完畢之后停線程池,關閉程序
                  try {
                      TimeUnit.SECONDS.sleep(20);
                      logger.info("待分析URL隊列大小: {}", SpiderQueue.waitingMineSize());
                      // 關閉線程池
                      threadPoolTaskExecutor.shutdown();
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }
          }

          在"// TODO:"之后的代碼邏輯這里是臨時的,等后邊章節完善之后,這里就慢慢去掉。

          最后

          要跑起這一節的代碼,需要在springboot項目main方法中加入如下代碼:

          ConfigurableApplicationContext context = SpringApplication.run(SpiderApplication.class, args);
          Spider spider = context.getBean(Spider.class);
          SpiderHtml startPage = new SpiderHtml();
          startPage.setUrl("$URL");
          startPage.setDepth(2);
          spider.start(startPage);

          $URL就是需要抓取的網頁地址。

          springboot項目啟動后,停止需要手動停止,目前沒有處理抓取完自動停止運行的邏輯。 運行結果如下圖:


          幻猿簡易爬蟲運行結果


          最后,這個章節完成之后整個項目的結構如下圖:


          幻猿簡易爬蟲項目結構


          關于我


          程序界的老猿,自媒體界的新寵 じ☆ve


          程序界的老猿,自媒體界的新寵 じ☆ve

          聯系方式:1405368512@qq.com

          在許多應用中,需要從URL中提取域名信息,以便進一步分析或處理。Python提供了強大的工具來執行這項任務。在本教程中,我們將學習如何使用Python從URL中提取域名,并提供示例代碼以幫助大家入門。

          URL結構分析

          通常一個URL分為以下幾個部分,它們是:

          • scheme ,指定我們可以用來獲取在線資源的協議,例如,HTTP/HTTPS
          • netloc , net 表示網絡,loc 表示位置;所以它表示URLs的網絡位置
          • path ,一個網絡瀏覽器用來訪問所提供的資源的特定途徑
          • params , 這些是path 元素的參數

          使用urllib庫解析URL

          Python的標準庫中有urllib模塊,它包含了處理URL的各種功能。我們可以使用urllib.parse來解析URL并提取域名部分。下面是如何使用它的示例代碼:

          pythonfrom urllib.parse import urlparse
          
          # 輸入URL
          url = "https://www.example.com/path/page.html"
          
          # 解析URL
          parsed_url = urlparse(url)
          
          # 提取域名
          domain = parsed_url.netloc
          
          print("提取的域名是:", domain)
          

          在這個示例中,我們首先導入了urllib.parse模塊,然后定義了一個URL字符串,接著使用urlparse函數來解析URL。最后,我們從解析結果中提取域名部分并打印出來。

          使用第三方庫tldextract

          除了標準庫中的urllib,還可以使用第三方庫tldextract來更方便地提取域名。tldextract庫可以提取頂級域名(TLD)、域名和子域名,而且不需要對URL進行手動解析。安裝命令如下:

          pythonpip install tldextract
          

          提取url代碼:

          pythonimport tldextract
          
          # 輸入URL
          url = "https://www.example.com/path/page.html"
          
          # 提取域名
          extractor = tldextract.TLDExtract()
          domain_info = extractor(url)
          
          domain = f"{domain_info.domain}.{domain_info.suffix}"
          
          print("提取的域名是:", domain)
          

          在這個示例中,我們導入了tldextract庫,定義了一個URL字符串,然后使用tldextract.TLDExtract()創建了一個域名提取器。最后,我們使用提取器來提取域名部分,并將其打印出來。

          使用第三方庫tldextract通常更方便,因為它可以處理各種URL格式,并且提供了更詳細的域名信息。

          總結

          本文主要介紹了如何使用Python從URL中提取域名,提取域名完成后,我們就可以將域名使用到我們需要的地方了。


          霍格沃茲測試開發學社|免費學習資料大放送,助你事半功倍! - 公眾號 - 測試人社區

          天碰到要在一個頁面獲取另外一個頁面url傳過來的參數,一開始很本能的想到了用 split(“?”)這樣一步步的分解出需要的參數。

          喜歡的朋友可以測試下,希望對大家有所幫助!


          js方法一:正則分析法,指定參數名獲取值。

          function getQueryString(name){

          var reg =new RegExp('(^|&)'+name+'=([^&]*)(&|$)','i');

          var r = window.location.search.substr(1).match(reg);

          if(r !=null){

          return unescape(r[2]);

          }

          return null;

          }

          // 這樣調用:

          // http://orzhtml.github.io?a=1&b=2&c=3

          console.log(getQueryString("a"));

          console.log(getQueryString("b"));

          console.log(getQueryString("c"));

          結果截圖:

          下面舉一個例子:

          若地址欄URL為:abc.html?id=123&url=http://orzhtml.github.io

          那么,但你用上面的方法去調用:alert(getQueryString("url"));

          則會彈出一個對話框:內容就是 http://orzhtml.github.io

          如果用:alert(getQueryString("id"));那么彈出的內容就是 123 啦;

          當然如果你沒有傳參數的話,比如你的地址是 abc.html 后面沒有參數,那強行輸出調用結果有的時候會報錯:

          所以我們要加一個判斷 ,判斷我們請求的參數是否為空,首先把值賦給一個變量:

          var myurl= getQueryString("url");

          if(myurl != null && myurl.toString().length>1) {

          alert(myurl);

          }


          js方法二:獲取所有參數這樣就不會報錯了,結果返回始終會是一個對象!

          function GetRequest(){

          var url = location.search;//獲取url中"?"符后的字串

          var theRequest ={};

          if(url.indexOf("?")!=-1){

          var str = url.substr(1);

          strs = str.split("&");

          for(var i =0; i < strs.length; i ++){

          theRequest[strs[i].split("=")[0]]= unescape(strs[i].split("=")[1]);

          }

          }

          return theRequest;

          }

          // 這樣調用

          // http://orzhtml.github.io?a=4&b=5&c=6

          var Request = {};

          Request = GetRequest();

          console.log(Request);

          console.log(Request['a']);

          console.log(Request['b']);

          console.log(Request['c']);

          結果截圖:


          本文內容均屬個人原創作品,轉載此文章須附上出處及原文鏈接。

          加關注,定時推送,互動精彩多,若你有更好的見解,歡迎留言探討!


          主站蜘蛛池模板: 国产一区二区三区小说| 亚洲日韩中文字幕无码一区| 国产av一区二区精品久久凹凸| 竹菊影视欧美日韩一区二区三区四区五区| 日本精品一区二区三本中文| 精品欧洲av无码一区二区14| AV鲁丝一区鲁丝二区鲁丝三区| 国产精品乱码一区二区三| 一区二区三区四区在线视频 | а天堂中文最新一区二区三区| 国产MD视频一区二区三区| 亚洲一区日韩高清中文字幕亚洲| 久久精品一区二区三区不卡| 中文字幕无线码一区二区| 色视频综合无码一区二区三区| 国产免费一区二区三区不卡| 一本大道在线无码一区| 中文字幕亚洲一区二区三区| 无码国产精品一区二区免费| 搜日本一区二区三区免费高清视频| 成人免费区一区二区三区| 久久一区二区三区精华液使用方法 | 日本精品高清一区二区| 亚洲字幕AV一区二区三区四区| 亚洲A∨精品一区二区三区| 97av麻豆蜜桃一区二区| 亚洲国产激情在线一区| 午夜DV内射一区二区| 伊人久久精品一区二区三区 | 亚洲欧美日韩中文字幕一区二区三区| 精品久久综合一区二区| 久久国产一区二区三区| 精品综合一区二区三区| 精品国产一区二区三区无码| 久久精品一区二区影院| 日韩色视频一区二区三区亚洲| 无码少妇一区二区三区浪潮AV| 无码人妻精品一区二区三区99不卡 | 一区二区三区在线|日本| 3D动漫精品一区二区三区| 日本一区精品久久久久影院|