前段時間搞了一個地方性民生資訊號,資訊嘛,都是我抄你的,你抄官媒的,小市民都喜歡奇聞異事,所以就存在一個需求,如何去定向抓取奇聞異事的地方號上的新聞,其實做起來很簡單,用邏輯回歸即可,這篇主要討論如何去抓取,在 C# 中大家都知道抓取通用的庫是 HtmlAgilityPack,但是這個庫主流的做法是采用 xpath 提取網頁內容,這就讓我很不爽了,畢竟不熟悉莫名的抵抗哈,像我這個年紀的碼農,被 Jquery 教育了至少 5-6 年,所以必須用 類Jquery 的方式,在 python 中有 cquery 做這件事情,那在 C# 中有沒有類似的方式呢? 嘿嘿,萬能的 github 上還真有。。。 就是本篇介紹的 CSQuery。
github的地址: https://github.com/zone117x/CsQuery 然后在vs中 nuget 一下即可:
一切都準備就緒了,那怎么用呢? 不著急,我以博客園舉兩個例子。
如上圖,要想獲取這里的 友情鏈接幾個大字,直接用 text() 肯定是不行的,默認情況它會將所有的子節點的文本也會抓到,如下圖:
那怎么處理呢? 可以用 jquery 提供的 contents 方法,然后在獲取的所有子節點中判斷是否有 文本節點,最后獲取文本節點的內容即可,如下代碼:
用js是搞定了,那用 CSQuery 代碼怎么搞定呢?模仿唄,如下代碼:
static void Main(string[] args)
{
var jquery = CQ.CreateDocument(new WebClient().DownloadString("http://cnblogs.com"));
var content = jquery["#friend_link"].Contents().Filter((dom) =>
{
return dom.NodeType == NodeType.TEXT_NODE;
}).Text();
Console.WriteLine(content);
}
我不知道用 xpath 提取這樣的內容麻不麻煩,不過用 jquery 方式不簡單,但輕車熟路。
有時候為了業務需要將某些 html 標簽改一下顏色,比如說將首頁的 tabmenu 中 博問 和 專區 改成紅色,如下圖:
那用 CSQuery 怎么處理呢? 如果玩過 jquery,一般來說步驟如下:
有了步驟,C#代碼如下:
static void Main(string[] args)
{
Config.HtmlEncoder = HtmlEncoders.None;
var jquery = CQ.CreateDocument(new WebClient().DownloadString("http://cnblogs.com"));
var html = jquery["#nav_left li"].Each(dom =>
{
var self = jquery[dom];
var text = self.Text();
if (text == "博問" || text == "專區")
{
self.Find("a").CssSet(new { color = "red" });
}
}).Render();
}
除了上面兩個操作方法外,你還可以使用 after,before,replaceAll,IS 等等一百來個實用的方法,這篇肯定也無法一一介紹了,大家有興趣可以下載下來看一看,搗鼓搗鼓。
除了抓取html中的元素,我覺得這玩意還可以用在發送郵件時操控郵件模板,畢竟在很久以前大家都是用jquery來繪制 html,所以用 CSQuery 也是可以的,相對使用 xslt 有利有弊吧,接下來做一個例子:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<ul id="main"></ul>
</body>
</html>
可以用 Append 將內容追加到 <ul> 節點內。
class Program
{
static void Main(string[] args)
{
Config.HtmlEncoder = HtmlEncoders.None;
var strlist = new string[2] { "1", "2" };
var path = Environment.CurrentDirectory + "\\2.html";
var jquery = CQ.CreateFromFile(path);
foreach (var str in strlist)
{
jquery.Find("#main").Append($"<li>{str}</li>");
}
var html = jquery.Render();
}
}
Render方法是將整個Dom渲染成html,但有時候你只需要得到你修改的那部分內容,而不是整個html,這就涉及到了部分渲染,可以用 RenderSelection 方法即可,代碼如下:
static void Main(string[] args)
{
Config.HtmlEncoder = HtmlEncoders.None;
var strlist = new string[2] { "1", "2" };
var path = Environment.CurrentDirectory + "\\2.html";
var jquery = CQ.CreateFromFile(path);
var current = jquery.Find("#main");
foreach (var str in strlist)
{
current.Append($"<li>{str}</li>");
}
var html = current.RenderSelection();
Console.WriteLine(html);
}
------------- output ----------------
<ul id="main"><li>1</li><li>2</li></ul>
Jquery 這種操作模式對我個人來說還是比較舒服的,畢竟熟! 不過在 html5 中也新增了 querySelector 和 querySelectorAll 支持 css3 選擇器,非常強大,可 jquery 不光在選擇器的靈活上,還在于對節點的靈活操作上,總的來說不是特別富交互的情況下可以懷舊一把。
人建議:學習 jQuery 前先掌握基本的 JavaScrpit 語法,特別是對函數要掌握,jQuery 基本上是使用函數。
jQuery 是一個輕量級 JavaScript 庫
jQuery 庫位于一個 JavaScript 文件中,其中包含了所有的 jQuery 函數,需要通過 <script>標簽引入 jQuery 庫才能進行使用
本地引入
共有兩個版本的 jQuery 可供下載 http://jQuery.com:一份是精簡過的,另一份是未壓縮的(供調試或閱讀)
從 Google 加載 CDN jQuery 核心文件( 版本可更換 )
src = http://ajax.googleapis.com/ajax/libs/jquery/1.4.0/jquery.min.js
從 Microsoft 加載 CDN jQuery 核心文件( 版本可更換 )
src = http://ajax.microsoft.com/ajax/jquery/jquery-1.4.min.js
基礎語法:$(selector).action()
美元符號($)定義 jQuery
選擇符(selector)“ 查詢 ” 和 “ 查找 ” HTML 元素
jQuery 的 action() 執行對元素的操作
文檔就緒函數
文檔就緒函數,用于在頁面加載成功后執行的指定代碼
如果在文檔沒有完全加載之前就運行函數,操作可能失敗
通常該函數用于替換 window.onload 事件,文檔就緒函數的執行效率更高
$(document).ready(function(){ code block });
可以簡寫為:
$(function(){ code block });
jQuery 使用 $ 符號作為 jQuery 的簡寫
jQuery 標識符
使用 jQuery 全名
jQuery(document).ready(function(){ jQuery("button").click(function(){ code block }); });
使用 jQuery 簡寫
$(function(){ $("button").click(function(){ code block }); });
自定義 jQuery 別名
var jq = $.noConflict(); jq(function(){ jq("button").click(function(){ code block }); });
注:因為 javascrpit 某些框架中也使用 $ 作為簡寫( 就像 jQuery ),noConflict() 方法是為了解決 javascrpit 框架之間符號沖突而定義的方法,它會釋放 $ 標識符的控制,這樣其他腳本也可以使用這個符號
jQuery 元素選擇器和屬性選擇器允許您通過標簽名、屬性名或內容對 HTML 元素進行選擇
jQuery 元素選擇器
jQuery 使用 CSS 選擇器來選取 HTML 元素
$(this) 當前 HTML 元素
$("p") 選取 <p> 元素
$("p.intro") 選取所有 class="intro" 的 <p> 元素
$("p#demo") 選取所有 id="demo" 的 <p> 元素
$("div#intro .head") 選取 id="intro" 的 <div> 元素中的所有 class="head" 的元素
jQuery 屬性選擇器
jQuery 使用 XPath 表達式來選擇帶有給定屬性的元素
$("[href]") 選取所有帶有href 屬性的元素
$("[href='#']") 選取所有帶有 href 值等于"#" 的元素
$("[href!='#']") 選取所有帶有 href 值不等于 "#" 的元素
$("[href$='.jpg']") 選取所有 href 值以 ".jpg" 結尾的元素
jQuery CSS 選擇器
jQuery CSS 選擇器可用于改變 HTML 元素的 CSS 屬性
把所有 p 元素的背景顏色更改為紅色:$("p").css("background-color","red")
jQuery 事件處理方法是 jQuery 中的核心函數
事件處理程序指的是當 HTML 中發生某些事件時所調用的方法。術語由事件“觸發”(或“激發”)經常會被使用
例子:按鈕的點擊事件被觸發時會調用一個函數
$("button").click(function() {..some code... } )
常用事件函數
$(document).ready(function) 將函數綁定到文檔的就緒事件(當文檔完成加載時)
$(selector).click(function) 觸發或將函數綁定到被選元素的點擊事件
$(selector).change(function) 觸發、或將函數綁定到指定元素的 change 事件
$(selector).dblclick(function) 觸發或將函數綁定到被選元素的雙擊事件
$(selector).focus(function) 觸發或將函數綁定到被選元素的獲得焦點事件
$(selector).mouseover(function) 觸發或將函數綁定到被選元素的鼠標懸停事件
效果通常綁定在某在事件上,例如通過點擊按鈕產生隱藏效果
常見的用于效果的函數
1.隱藏、顯示、切換
- 隱藏 `$(selector).hide(speed,callback)` : `$("p").hide();` - 顯示`$(selector).show(speed,callback)` : `$("p").show(1000);` - 切換隱藏/顯示`$(selector).toggle(speed,callback)` : `$("p").toggle();`
speed 和 callback 都是可選參數
speed 參數規定顯示/隱藏的速度,可選值為:”slow”、”fast” 或毫秒值
callback 參數是顯示/隱藏完成后所執行的函數名稱
2.淡入、淡出
- 淡入 `$(selector).fadeIn(speed,callback)` : `$("#div1").fadeIn("slow");` - 淡出 `$(selector).fadeOut(speed,callback)` : `$("#div3").fadeOut(3000);` - 切換淡入/淡出 `$(selector).fadeToggle(speed,callback)` : ` $("#div1").fadeToggle();` - 漸變為特定透明度 `$(selector).fadeTo(speed,opacity,callback)` :`$("#div2").fadeTo("slow",0.4);`
speed 和 callback 都是可選參數,opacity 為必需參數
speed 參數規定淡入/淡出的速度,可選值為:”slow”、”fast” 或毫秒值
callback 參數是顯示/隱藏完成后所執行的函數名稱
opacity 參數將淡入淡出效果設置為給定的不透明度(值介于 0 與 1 之間)
3.滑動
- 向下滑動 `$(selector).slideDown(speed,callback)` : `$("#panel").slideDown();` - 向上滑動 `$(selector).slideUp(speed,callback)` : `$("#panel").slideUp();` - 切換向上滑動/向下滑動 `slideToggle()` : `$("#panel").slideToggle();`
speed 和 callback 都是可選參數
speed 參數規定向上滑動/向下滑動的速度,可選值為:”slow”、”fast” 或毫秒值
callback 參數是向上滑動/向下滑動完成后所執行的函數名稱
4.動畫
- 自定義動畫 `$(selector).animate({params},speed,callback)`
params 是必需參數, speed 和 callback 是可選參數
params 參數定義形成動畫的 CSS 屬性
speed 參數規定效果的時長,可選值為:”slow”、”fast” 或毫秒值
callback 參數是動畫完成后所執行的函數名稱
注: 默認地,所有 HTML 元素都有一個靜態位置,且無法移動,如需對位置進行操作,要記得首先把元素的 CSS position 屬性設置為 relative、fixed 或 absolute!
- 停止動畫 ·`$(selector).stop(stopAll,goToEnd);`
stopAll 和 goToEnd 都是可選參數
stopAll 參數規定是否應該清除動畫隊列。默認是 false,即僅停止活動的動畫,允許任何排入隊列的動畫向后執行
goToEnd 參數規定是否立即完成當前動畫。默認是 false。
默認地,stop() 會清除在被選元素上指定的當前動畫
實例
使用絕對值
$("div").animate({ left:'250px', opacity:'0.5', height:'150px', width:'150px' });
使用相對值
$("button").click(function(){ $("div").animate({ left:'250px', height:'+=150px', width:'+=150px' }); });
使用隊列功能 ( 逐一進行 animate 調用 )
$("button").click(function(){ var div=$("div"); div.animate({height:'300px',opacity:'0.4'},"slow"); div.animate({width:'300px',opacity:'0.8'},"slow"); div.animate({height:'100px',opacity:'0.4'},"slow"); div.animate({width:'100px',opacity:'0.8'},"slow"); });
5.方法連接
允許我們在相同的元素上運行多條 jQuery 命令,一條接著另一條,這樣的話,瀏覽器就不必多次查找相同的元素。如需鏈接一個動作,您只需簡單地把該動作追加到之前的動作上
例如: 把 css(), slideUp() 和 slideDown() 鏈接在一起。”p1” 元素首先會變為紅色,然后向上滑動,然后向下滑動
$("#p1").css("color","red").slideUp(2000).slideDown(2000);
對內容操作
1.獲取內容
- `$(selector).text();` 設置或返回所選元素的文本內容 - `$(selector).html();` 設置或返回所選元素的內容(包括 HTML 標記) - `$(selector).val();` 設置或返回表單字段的值
2.設置內容
- `$(selector).text(string);` 設置所選元素的文本內容 - `$(selector).val(string);` 設置所選元素的內容(包括 HTML 標記) - `$(selector).html(string);` 設置表單字段的值
3.回調函數
i:被選元素列表中當前元素的下標
origText:原始(舊的)值
res:以函數新值返回您希望使用的字符串
- `$(selector).text(function(i,origText){return res;});` 設置或返回所選元素的文本內容 - `$(selector).val(function(i,origText){return res;});` 設置或返回所選元素的內容(包括 HTML 標記) - `$(selector).html(function(i,origText){return res;});` 設置或返回表單字段的值
對屬性操作
1.獲取屬性
- `$(selector).attr("attribute");` 獲取指定元素的所選屬性
2.設置屬性
- `$(selector).attr("attribute","value");` 設置所選屬性的值 - `$(selector).attr({"attribute1":"value1", "attribute2":"value2"});` 同時設置多個屬性的值
3.attr() 的回調函數
i : 被選元素列表中當前元素的下標
origValue : 原始(舊的)值
res : 以函數新值返回您希望使用的字符串
- `$(selector).attr("attribute",function(i,origValue){return res});`
對元素/內容操作
與前面的 對內容操作 不同的是:上面的三個方法會將原來的值覆蓋,而這里的方法是在原值基礎上進行修改
1.添加
參數可以是多個,如果多個含有 html 的內容,則相當于增加了多個 html 元素
- `$(selector).append("text");` 在被選元素的結尾插入內容 - `$(selector).prepend("text");` 在被選元素的開頭插入內容 - `$(selector).prepend("text");` 在被選元素之后插入內容 - `$(selector).before("text");` 在被選元素之前插入內容
2.刪除
- `$(selector).remove();` 刪除被選元素(及其子元素) - `$(selector).empty();` 從被選元素中刪除子元素 - `$(selector).remove(selector);` 刪除指定選擇器的元素
對 CSS 元素操作
前三種方法是針對已經寫好的樣式
- `$(selector).addClass("className1 className2");` 向被選元素添加一個或多個類 - `$(selector).removeClass("className1 className2");` 從被選元素刪除一個或多個類 - `$(selector).toggleClass("className");` 對被選元素進行添加/刪除類的切換操作 - `$(selector).css();`返回樣式屬性 - `$(selector).css("attribute","value");`設置單個樣式屬性 - `$(selector).css({"propertyname":"value","propertyname":"value",...});`設置多個樣式屬性
對尺寸操作
注意參數,中間四種沒有沒有參數,不能進行設置
- `$(selector).width("text");` 設置或返回元素的寬度(不包括內邊距、邊框或外邊距) - `$(selector).height("text");` 設置或返回元素的高度(不包括內邊距、邊框或外邊距) - `$(selector).innerWidth();`返回元素的寬度(包括內邊距) - `$(selector).innerHeight(");`返回元素的高度(包括內邊距) - `$(selector).outerWidth();`返回元素的寬度(包括內邊距和邊框) - `$(selector).outerHeight();` 返回元素的高度(包括內邊距和邊框) - `$(selector).outerWidth(true);`返回元素的寬度(包括內邊距、邊框和外邊距) - `$(selector).outerHeight(true);` 返回元素的高度(包括內邊距、邊框和外邊距)
祖先
向上遍歷 DOM 樹
- `$(selector).parent();` 返回被選元素的直接父元素,該方法只會向上一級對 DOM 樹進行遍歷 - `$(selector).parents();` 返回被選元素的所有祖先元素,它一路向上直到文檔的根元素 (<html>) - `$(selector).parents(selector);` 返回經過過濾的所有祖先元素,它一路向上直到文檔的根元素 (<html>) - `$(selector).parentsUntil() ;`返回介于兩個給定元素之間的所有祖先元素
祖先
向下遍歷 DOM 樹,以查找元素的后代
- `$(selector).children();` 返回被選元素的所有直接子元素,該方法只會向下一級對 DOM 樹進行遍歷 - `$(selector).children(selector);` 返回被選元素的經過過濾的子元素,該方法只會向下一級對 DOM 樹進行遍歷 - `$(selector).find("selector");` 返回被選元素的后代元素,一路向下直到最后一個后代(此方法必須有參數,如果是全部則為 "*" )
同胞
DOM 樹中遍歷元素的同胞元素
- `$(selector).siblings(selector);` 返回被選元素的所有同胞元素(selector可選) - `$(selector).next();` 返回被選元素的下一個同胞元素 - `$(selector).nextAll();` 返回被選元素的所有跟隨的同胞元素 - `$(selector).nextUntil(selecotr);` 返回介于兩個給定參數之間的所有跟隨的同胞元素 - prev(), prevAll() 以及 prevUntil() 方法的工作方式與上面的方法類似,只不過方向相反而已:它們返回的是前面的同胞元素(在 DOM 樹中沿著同胞元素向后遍歷,而不是向前)
過濾
允許您基于其在一組元素中的位置來選擇一個特定的元素
- `$(selector).first();` 返回被選元素的首個元素 - `$(selector).last();` 返回被選元素的最后一個元素 - `$(selector).eq();` 返回被選元素中帶有指定索引號的元素(索引號從 0 開始) - `$(selector).filter(selector);` 不匹配這個標準的元素會被從集合中刪除,匹配的元素會被返回 - `$(selector).not(selector);` not() 方法與 filter() 相反,返回不匹配標準的所有元素
AJAX = 異步 JavaScript 和 XML(Asynchronous JavaScript and XML)
簡短地說,在不重載整個網頁的情況下,AJAX 通過后臺加載數據,并在網頁上進行顯示
load 方法
- `$(selector).load(URL,data,callback);` 方法從服務器加載數據,并把返回的數據放入被選元素中
必需的 URL 參數規定您希望加載的 URL。
可選的 data 參數規定與請求一同發送的查詢字符串鍵/值對集合。
可選的 callback 參數是 load() 方法完成后所執行的函數名稱
callback 回調函數
$(selector).load(URL,data,function(responseTxt,statusTxt,xhr){});
responseTxt - 包含調用成功時的結果內容
statusTXT - 包含調用的狀態
xhr - 包含 XMLHttpRequest 對象
responseTxt - 包含調用成功時的結果內容
statusTXT - 包含調用的狀態
xhr - 包含 XMLHttpRequest 對象
get/post 方法
必需的 URL 參數規定您希望請求的 URL
可選的 callback 參數是請求成功后所執行的函數名
- `$.get(URL,callback);` 通過 HTTP GET 請求從服務器上請求數據
GET - 從指定的資源請求數據
GET 基本上用于從服務器獲得(取回)數據。注釋:GET 方法可能返回緩存數據
- `$.post(URL,data,callback);` 通過 HTTP POST 請求從服務器上請求數據
data 是要提交給服務器的數據,如果數據有多個,使用 json 格式
POST - 向指定的資源提交要處理的數據
POST 也可用于從服務器獲取數據。不過,POST 方法不會緩存數據,并且常用于連同請求一起發送數據
回調函數
data : 存有被請求頁面的內容
status : 存有請求的狀態( success/fail )
function(data,status){ alert("Data: " + data + "\nStatus: " + status); });
注意: ajax 不能訪問本地文件,需要解決跨域訪問的問題
么是JS延遲加載?
JS延遲加載,也就是等頁面加載完成之后再加載JavaScript文件
為什么讓JS實現延遲加載?
js的延遲加載有助于提高頁面的加載速度。
Js延遲加載的方式有哪些?一般有以下幾種方式:
·defer屬性
·async屬性
·動態創建DOM方式
·使用jQuery的getScript方法
·使用setTimeout延遲方法
·讓JS最后加載
HTML 4.01為<script>標簽定義了defer屬性。標簽定義了defer屬性元素中設置defer屬性,等于告訴瀏覽器立即下載,但延遲執行標簽定義了defer屬性。
用途:表明腳本在執行時不會影響頁面的構造。也就是說,腳本會被延遲到整個頁面都解析完畢之后再執行在<script>元素中設置defer屬性,等于告訴瀏覽器立即下載,但延遲執行
<!DOCTYPE html>
<html>
<head>
<script src="test1.js" defer="defer"></script>
<script src="test2.js" defer="defer"></script>
</head>
<body>
<!--這里放內容-->
</body>
</html>
說明:雖然<script>元素放在了<head>元素中,但包含的腳本將延遲瀏覽器遇到</html>標簽后再執行HTML5規范要求腳本按照它們出現的先后順序執行。在現實當中,延遲腳本并不一定會按照順序執行defer屬性只適用于外部腳本文件。支持HTML5的實現會忽略嵌入腳本設置的defer屬性
HTML5 為<script>標簽定義了async屬性。與defer屬性類似,都用于改變處理腳本的行為。同樣,只適用于外部腳本文件。標簽定義了async屬性。與defer屬性類似,都用于改變處理腳本的行為。同樣,只適用于外部腳本文件。
目的:不讓頁面等待腳本下載和執行,從而異步加載頁面其他內容。異步腳本一定會在頁面 load 事件前執行。不能保證腳本會按順序執行
<!DOCTYPE html>
<html>
<head>
<script src="test1.js" async></script>
<script src="test2.js" async></script>
</head>
<body>
<!--這里放內容-->
</body>
</html>
async和defer一樣,都不會阻塞其他資源下載,所以不會影響頁面的加載。
缺點:不能控制加載的順序
//這些代碼應被放置在</ body>標簽前(接近HTML文件底部)
<script type="text/javascript">
function downloadJSAtOnload() {
varelement = document .createElement("script");
element.src = "defer.js";
document.body.appendChild(element);
}
if (window. addEventListener)
window.addEventListener("load" ,downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload) ;
else
window. onload =downloadJSAtOnload;
</script>
$.getScript("outer.js" , function(){ //回調函數,成功獲取文件后執行的函數
console.log(“腳本加載完成")
});
<script type="text/javascript" >
function A(){
$.post("/1ord/1ogin" ,{name:username,pwd:password},function(){
alert("Hello");
});
}
$(function (){
setTimeout('A()', 1000); //延遲1秒
})
</script>
把js外部引入的文件放到頁面底部,來讓js最后引入,從而加快頁面加載速度例如引入外部js腳本文件時,如果放入html的head中,則頁面加載前該js腳本就會被加載入頁面,而放入body中,則會按照頁面從上倒下的加載順序來運行JavaScript的代碼。所以我們可以把js外部引入的文件放到頁面底部,來讓js最后引入,從而加快頁面加載速度。
上述方法2也會偶爾讓你收到Google頁面速度測試工具的“延遲加載javascript”警告。所以這里的解決方案將是來自Google幫助頁面的推薦方案。
//這些代碼應被放置在</body>標簽前(接近HTML文件底部)
<script type= "text/javascript">
function downloadJSAtonload() {
var element = document.createElement("script");
element.src = "defer.js";
document.body.appendChild(element);
}
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent )
window.attachEvent("onload", downloadJSAtonload);
else window.onload = downloadJSAtOnload;
</script>
這段代碼意思等到整個文檔加載完后,再加載外部文件“defer.js”。
使用此段代碼的步驟:
6.1)復制上面代碼
6.2)粘貼代碼到HTML的標簽前 (靠近HTML文件底部)
6.3)修改“defer.js”為你的外部JS文件名
6.4)確保文件路徑是正確的。例如:如果你僅輸入“defer.js”,那么“defer.js”文件一定與HTML文件在同一文件夾下。
注意:
這段代碼直到文檔加載完才會加載指定的外部js文件。因此,不應該把那些頁面正常加載需要依賴的javascript代碼放在這里。而應該將JavaScript代碼分成兩組。一組是因頁面需要而立即加載的javascript代碼,另外一組是在頁面加載后進行操作的javascript代碼(例如添加click事件。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。