JavaScript 提供了許多方法來檢索和更改顯示在瀏覽器地址欄中的當前 URL,所有這些方法都使用Location對象,它是對象的一個?屬性Window。
您可以創建一個具有當前URL的新對象,如下所示:
let loc=window.location;
let url=loc.href;
location屬性
Location 接口不繼承任何屬性,但是實現了那些來自 URLUtils 的屬性。
Location.href包含整個URL的一個DOMStringLocation.protocol包含URL對應協議的一個DOMString,最后有一個":"。
Location.host包含了域名的一個DOMString,可能在該串最后帶有一個":"并跟上URL的端口號。
Location.hostname包含URL域名的一個DOMString。
Location.port包含端口號的一個DOMString。
Location.pathname包含URL中路徑部分的一個DOMString,開頭有一個“/"。Location.search 包含URL參數的一個DOMString,開頭有一個“?”。
Location.hash包含塊標識符的DOMString,開頭有一個“#”。
Location.username包含URL中域名前的用戶名的一個DOMString。
Location.password包含URL域名前的密碼的一個 DOMString。
Location.origin只讀包含頁面來源的域名的標準形式DOMString。
Location沒有繼承任何方法,但實現了來自URLUtils的方法。
Location.assign()加載給定URL的內容資源到這個Location對象所關聯的對象上。
Location.reload()重新加載來自當前 URL的資源。他有一個特殊的可選參數,類型為 Boolean,該參數為true時會導致該方法引發的刷新一定會從服務器上加載數據。如果是 false或沒有制定這個參數,瀏覽器可能從緩存當中加載頁面。
Location.replace()用給定的URL替換掉當前的資源。與 assign() 方法不同的是用 replace()替換的新頁面不會被保存在會話的歷史 History中,這意味著用戶將不能用后退按鈕轉到該頁面。
Location.toString()返回一個DOMString,包含整個URL。 它和讀取URLUtils.href的效果相同。但是用它是不能夠修改Location的值的。
上一節(爬蟲系列(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分析操作的工具包,不清楚的可以去搜索看看,之后章節涉及到分析的部分也會用到。
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
avaweb
在我們平常的javaweb開發中,前臺頁面經常會用到獲取url中的參數,大多數程序員可能直接
用window.location.href 獲取到當前頁面的url,然后再用substring去截取字符串,這樣的話很麻煩。
當然我上面所說的是在html的文件中,如果你是用的jsp的話,那就很簡單了。用el表達式我們可以很輕松的獲取url中的參數:${param.paramName}
好了,言歸正傳,那如何在html中獲取url中的參數了?
我們可以單獨封裝一個函數來達到這個目的。以后只要是要獲取url的參數,直接調用這個函數就可以了。
function get_param(name, url){
if(!url) url=window.location.href;
name=name.replace(/[\[\]]/g,"\$&");
var regex=newRegExp("[?&]"+ name +"(=([^&#]*)|&|#|$)"),
results=regex.exec(url);
if(!results) return null;
if(!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g," "));
}
我在后續的文章中,會分享更多更實用的開發小技巧給大家,希望大家多多關注!
*請認真填寫需求信息,我們會在24小時內與您取得聯系。