Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
ello,親愛(ài)的小伙伴們,歡迎瀏覽“使用CefSharp和Javascript實(shí)現(xiàn)網(wǎng)絡(luò)爬蟲(chóng)”。
本篇是第2篇,介紹在實(shí)現(xiàn)爬蟲(chóng)過(guò)程中會(huì)用到的Javascript和C#主要知識(shí)點(diǎn)。在使用CefSharp和Javascript實(shí)現(xiàn)網(wǎng)絡(luò)爬蟲(chóng)過(guò)程中,我使用到的C#和Javascript知識(shí)主要包括三個(gè)方面:一是Javascript的Dom操作;二是CefSharp中Javascript和C#之間的調(diào)用和交互;三是C#委托使用,用于接收到數(shù)據(jù)后的回調(diào)處理。
網(wǎng)絡(luò)爬蟲(chóng)采用Javascript的DOM操作來(lái)抓取目標(biāo)數(shù)據(jù),并通過(guò)CefSharp提供的Javascript和C#交互方法,把目標(biāo)數(shù)據(jù)傳遞給C#代碼進(jìn)行處理。下面我將分別進(jìn)行記錄,分享給感興趣的小伙伴。
一、Javascript原生DOM操作
HTML通過(guò)瀏覽器解析后形成DOM樹(shù),DOM中每個(gè) HTML標(biāo)簽都是一個(gè)節(jié)點(diǎn)元素,包括屬性、方法、子孫節(jié)點(diǎn)。Javascript有一套操作HTML的DOM編程接口,通過(guò)DOM編程接口能夠操作到每個(gè)節(jié)點(diǎn)元素(即HTML標(biāo)簽),支持增、刪、改、查操作。
1、查找獲取節(jié)點(diǎn)
查找獲取HTML節(jié)點(diǎn)元素,可能通過(guò)document的get方法,或者使用document 的querySelector()和querySelectorAll()方法實(shí)現(xiàn)。
方法1:通過(guò)document的get方法
var elem=document.getElementById(idName) ;//通過(guò)id號(hào)獲取元素,返回一個(gè)元素對(duì)象
var elem=document.getElementsByClassName(className) ;//通過(guò)class獲取元素,返回元素?cái)?shù)組
var elem document.getElementsByTagName(tagName);//通過(guò)標(biāo)簽名獲取元素,返回元素?cái)?shù)組
以上方法可以串聯(lián)使用,例如:
// 先定位ID為idName的節(jié)點(diǎn),再返回其內(nèi)部所有名稱為tagName的節(jié)點(diǎn):
var elem=document.getElementById(idName).getElementsByTagName(tagName);
// 先定位ID為idName的節(jié)點(diǎn),再返回其內(nèi)部所有class包含className的節(jié)點(diǎn):
var elem=document.getElementById(idName).getElementsByClassName(className);
方法二:使用document 的querySelector()和querySelectorAll()方法
var elem=document.querySelector('# idName ');// 通過(guò)querySelector獲取id為idName的節(jié)點(diǎn)
var elem=document.querySelectorAll('div');// 通過(guò)querySelectorAll獲取所有的div節(jié)點(diǎn)
2、獲取/設(shè)置元素的屬性值
通過(guò)document的get方法,或者使用document 的querySelector()和querySelectorAll()方法,得到節(jié)點(diǎn)對(duì)象后,可進(jìn)一步可獲取節(jié)點(diǎn)的屬性值。
elem.parentNode;//獲取當(dāng)前元素的父節(jié)點(diǎn)
elem.chlidren;//獲取當(dāng)前元素子節(jié)點(diǎn)
elem.chilidNodes;//獲取當(dāng)前元素子節(jié)點(diǎn)
elem.firstChild;//獲取當(dāng)前元素的第1個(gè)子節(jié)點(diǎn)
elem.lastChild;//獲取當(dāng)前元素的最后1個(gè)子節(jié)點(diǎn)
elem.innerHTML?? //獲取元素的內(nèi)部文本
elem.innerText; //獲取當(dāng)前元素的內(nèi)部文本值,只是文本內(nèi)容,不包括html代碼
此外,通過(guò)getAttribute、setAttribute可以實(shí)現(xiàn)對(duì)屬性值的獲取或設(shè)置。
elem.getAttribute(attributeName);//傳入屬性名稱,獲取對(duì)應(yīng)屬性的屬性值
elem.setAttribute(attributeName,attributeValue); //傳入屬性名稱,以及屬性值
二、jQuery操作HTML的DOM
對(duì)于支持jQuery的站點(diǎn),可以直接使用jQuery方便地進(jìn)行DOM操作。
jQuery對(duì)Javascript的DOM操作方法進(jìn)行了封裝,通過(guò)jQuery 選擇器能夠?qū)?HTML 節(jié)點(diǎn)元素或節(jié)點(diǎn)元素組進(jìn)行操作。jQuery 選擇器通過(guò)節(jié)點(diǎn)的 ID、類(lèi)、類(lèi)型、屬性、屬性值等查找/選擇HTML 節(jié)點(diǎn)元素,jQuery 選擇器以$符號(hào)開(kāi)頭。
1、查找獲取節(jié)點(diǎn)
(1)元素選擇器
使用節(jié)點(diǎn)名選取元素,例如在頁(yè)面中選取所有 <div> 元素:$('div')
(2)#id選擇器
使用 HTML 元素的 ID屬性選取指定的元素,例如在頁(yè)面中選取id='myid'的 <div id='myid'> 元素:$('#myid')
(3).class 選擇器
使用 class 查找元素,例如在頁(yè)面中選取class='myclass'的 <div class='myclass'>元素:$(".myclass")
2、獲取/設(shè)置元素的屬性值:
通過(guò)attr() 、html()、val()方法設(shè)置或返回被選元素的屬性值:
$(selector).attr(attribute); //獲取被選元素的屬性值
$(selector).attr(attribute,value);//設(shè)置被選元素的屬性和值
$(selector).html();//獲取或設(shè)置被選元素的內(nèi)容 (innerHTML)
$(selector).val();//獲取或設(shè)置被選元素的值
三、DOM操作實(shí)踐
使用Chrome瀏覽器,打開(kāi)以下網(wǎng)址:
https://www.toutiao.com/c/user/3601650358695789/#mid=1652236062202883
(1)按“F12”打開(kāi) “開(kāi)發(fā)者工具”窗口,在“Elements”面板可以看到頁(yè)面的DOM結(jié)構(gòu)。
(2)點(diǎn)擊左上角"箭頭"圖標(biāo),在頁(yè)面中選擇文章標(biāo)題,在“開(kāi)發(fā)者工具”中可以看到被選中元素高亮顯示。
(3)在“開(kāi)發(fā)者工具”中“右鍵”點(diǎn)擊高亮顯示內(nèi)容,在彈出菜單中選擇Copy。
(4)選擇“Copy selector”
(5)點(diǎn)擊開(kāi)發(fā)者工具的“Console”選項(xiàng),在窗口中進(jìn)行如下輸入:
a) 輸入"//" ,然后鍵盤(pán)按下"Ctrl"+"V" 粘貼上述操作獲取的HTML元素選擇字符串,或者在輸入行“點(diǎn)擊右鍵”,選擇“粘貼(P)”,粘貼上述操作獲取的HTML元素選擇字符串,字符串為:
#wrapper > div.left > div:nth-child(2) > div > div:nth-child(3) > div > ul > li > div > div.normal.rbox > div > div.title-box > a
b) 輸入 var elem=$("XXX"),其中XXX是"Ctrl"+"V" 粘貼的字符串
c) 輸入 elem回車(chē),即可獲得我們選中的文章標(biāo)題元素
d) 輸入 elem.href ,即可獲得文章標(biāo)題的URL鏈接地址
e) 輸入 elem.innerText,即可獲得文章標(biāo)題字符串。
這樣我們就獲得了文章標(biāo)題和對(duì)應(yīng)的URL地址,后面通過(guò)CefSharp中Javascript和C#之間的調(diào)用和交互方法,可將標(biāo)題和對(duì)應(yīng)的URL地址傳遞給C#進(jìn)行處理存儲(chǔ)、打開(kāi)鏈接獲取文章詳細(xì)內(nèi)容等。本篇介紹了Javascript的DOM操作,后面我將對(duì)C#委托使用、CefSharp中Javascript和C#之間的調(diào)用和交互進(jìn)行介紹,敬請(qǐng)指正。
象語(yǔ)法樹(shù)(Abstract Syntax Trees),簡(jiǎn)稱AST,如果您正在編寫(xiě)代碼,那么 AST 很可能已經(jīng)參與了您的開(kāi)發(fā)流程。它們?yōu)槟拈_(kāi)發(fā)流程的許多部分提供動(dòng)力。 有些人可能在編譯器的上下文中聽(tīng)說(shuō)過(guò)它們,但它們被用于各種工具中。 即使您不編寫(xiě)通用開(kāi)發(fā)工具,AST 也可能是您工具帶中的有用工具。 在這篇文章中,我們將討論什么是 AST,它們?cè)谀睦锸褂靡约叭绾卫盟鼈儭?/p>
什么是AST
抽象語(yǔ)法樹(shù)或 AST 是代碼的樹(shù)型數(shù)據(jù)結(jié)構(gòu)表示。 它們是編譯器工作方式的基本部分。 當(dāng)編譯器轉(zhuǎn)換某些代碼時(shí),基本上有以下步驟:
詞法分析又名標(biāo)記化
在此步驟中,您編寫(xiě)的代碼將被轉(zhuǎn)換為一組描述代碼不同部分的標(biāo)記。 這與基本語(yǔ)法突出顯示使用的方法基本相同。 這些標(biāo)記令牌不了解事物如何組合在一起,并且僅關(guān)注文件的組件。
你可以想象這就像你將一個(gè)文本分解成單詞。 您可能能夠區(qū)分標(biāo)點(diǎn)符號(hào)、動(dòng)詞、名詞、數(shù)字等,但在這個(gè)階段,您對(duì)句子的組成部分或句子如何組合沒(méi)有任何更深入的了解。
語(yǔ)法分析又名解析
這是我們將標(biāo)記列表轉(zhuǎn)換為抽象語(yǔ)法樹(shù)的步驟。 它將我們的標(biāo)記轉(zhuǎn)換為表示代碼實(shí)際結(jié)構(gòu)的樹(shù)。 以前在標(biāo)記中我們只有一對(duì) (),現(xiàn)在我們知道它是函數(shù)調(diào)用、函數(shù)定義、分組還是其他東西。
這里的等價(jià)物是將我們的單詞列表轉(zhuǎn)換為表示諸如句子之類(lèi)的數(shù)據(jù)結(jié)構(gòu),某個(gè)名詞在句子中扮演什么角色,或者我們是否在列表中。
另一個(gè)可以與之比較的例子是 DOM。 上一步只是將 HTML 分解為“標(biāo)簽”和“文本”,而這一步將生成表示為 DOM 樹(shù)的層次結(jié)構(gòu)。
需要注意的一件事是沒(méi)有“單一”的 AST 格式。 它們可能會(huì)有所不同,這取決于您要轉(zhuǎn)換為 AST 的語(yǔ)言以及您用于解析的工具。 在 JavaScript 中,一個(gè)通用標(biāo)準(zhǔn)是 ESTree,但您會(huì)看到不同的工具可能會(huì)添加不同的屬性。
一般來(lái)說(shuō),AST 是一種樹(shù)結(jié)構(gòu),其中每個(gè)節(jié)點(diǎn)至少有一個(gè)類(lèi)型來(lái)指定它所代表的內(nèi)容。
代碼生成
此步驟本身可以是多個(gè)步驟。 一旦我們有了抽象語(yǔ)法樹(shù),我們就可以操作它,也可以將它“打印”到不同類(lèi)型的代碼中。 使用 AST 操作代碼比直接在代碼上作為文本或標(biāo)記列表執(zhí)行這些操作更安全。
操縱文本總是很危險(xiǎn)的; 它顯示最少的上下文。 如果您曾經(jīng)嘗試使用字符串替換或正則表達(dá)式來(lái)操作文本,您可能會(huì)注意到很容易出錯(cuò)。而且不容易調(diào)試。
甚至操縱令牌也不容易。 雖然我們可能知道變量是什么,但如果我們想重命名它,我們將無(wú)法深入了解變量的范圍或可能與之沖突的任何變量。
AST 提供了有關(guān)代碼結(jié)構(gòu)的足夠信息,我們可以更有信心地對(duì)其進(jìn)行修改。 例如,我們可以確定變量的聲明位置,并確切地知道由于樹(shù)結(jié)構(gòu)而影響程序的哪個(gè)部分。
一旦我們操縱了樹(shù),我們就可以打印樹(shù)以輸出任何預(yù)期的代碼輸出。 例如,如果我們要構(gòu)建一個(gè)像 TypeScript 編譯器這樣的編譯器,我們會(huì)輸出 JavaScript,而另一個(gè)編譯器可能會(huì)輸出機(jī)器代碼。
同樣,使用 AST 更容易實(shí)現(xiàn)這一點(diǎn),因?yàn)橄嗤Y(jié)構(gòu)的不同輸出可能具有不同的格式。 使用更線性的輸入(如文本或標(biāo)記列表)生成輸出會(huì)相當(dāng)困難。
如何處理 AST?
理論涵蓋了哪些實(shí)際生活中的 AST 用例? 我們討論了編譯器,但我們并不是整天都在構(gòu)建編譯器。
AST 的用例很廣泛,通常可以分為三個(gè)總體操作:讀取、修改和打印。 它們是一種添加劑,這意味著如果您正在打印 AST,那么您以前也閱讀過(guò) AST 并對(duì)其進(jìn)行修改的可能性很高。 但我們將介紹每個(gè)主要關(guān)注一個(gè)用例的示例。
讀取/遍歷 AST
從技術(shù)上講,使用 AST 的第一步是解析文本以創(chuàng)建 AST,但在大多數(shù)情況下,提供解析步驟的庫(kù)也提供了一種遍歷 AST 的方法。遍歷 AST 意味著訪問(wèn)樹(shù)的不同節(jié)點(diǎn)以獲取細(xì)節(jié)或執(zhí)行操作。
最常見(jiàn)的用例之一是 linting。 例如,ESLint 使用 espree 生成 AST,如果您想編寫(xiě)任何自定義規(guī)則,您將根據(jù)不同的 AST 節(jié)點(diǎn)編寫(xiě)這些規(guī)則。 ESLint 文檔有大量關(guān)于如何構(gòu)建自定義規(guī)則、插件和格式化程序的文檔。
修改/轉(zhuǎn)換 AST
如前所述,與將代碼修改為標(biāo)記或原始字符串相比,擁有 AST 使修改所述樹(shù)更容易、更安全。您可能想要使用 AST 修改某些代碼的原因有很多種。
例如,Babel 修改 AST 以向下編譯新功能或?qū)?JSX 轉(zhuǎn)換為函數(shù)調(diào)用。例如,當(dāng)您編譯 React 或 Preact 代碼時(shí)會(huì)發(fā)生這種情況。
另一個(gè)用例是捆綁代碼。在模塊的世界中,捆綁代碼通常比將文件附加在一起要復(fù)雜得多。更好地了解各個(gè)文件的結(jié)構(gòu)可以更輕松地合并這些文件并在必要時(shí)調(diào)整導(dǎo)入和函數(shù)調(diào)用。如果您查看 webpack、parcel 或 rollup 等工具的代碼庫(kù),您會(huì)發(fā)現(xiàn)它們都使用 AST 作為其捆綁工作流程的一部分。
打印 AST
在大多數(shù)情況下,打印和修改 AST 是齊頭并進(jìn)的,因?yàn)槟仨気敵鰟倓傂薷牡?AST。 但是,雖然像 recast 這樣的一些庫(kù)明確專(zhuān)注于以與原始代碼樣式相同的代碼樣式打印 AST,但也有各種用例,您希望以不同的方式顯式打印您的 AST。
例如,Prettier 使用 AST 根據(jù)您的配置重新格式化您的代碼,而無(wú)需更改代碼的內(nèi)容/含義。 他們這樣做的方式是將您的代碼轉(zhuǎn)換為完全與格式無(wú)關(guān)的 AST,然后根據(jù)您的規(guī)則重寫(xiě)它。
其他常見(jiàn)的用例是用不同的目標(biāo)語(yǔ)言打印代碼或構(gòu)建自己的縮小工具。
您可以使用幾種不同的工具來(lái)打印 AST,例如 escodegen 或 astring。 您還可以根據(jù)您的用例構(gòu)建自己的格式化程序,或者為 Prettier 構(gòu)建一個(gè)插件。
最后:
雖然 AST 可能是大多數(shù)開(kāi)發(fā)人員每天都不會(huì)使用的東西,但我相信了解它對(duì)今后的工作會(huì)有幫助。感謝閱讀。
瀏覽器訪問(wèn)網(wǎng)站時(shí),頁(yè)面各不相同,你有沒(méi)有想過(guò)它為何會(huì)呈現(xiàn)這個(gè)樣子呢?本節(jié)中,我們就來(lái)了解一下網(wǎng)頁(yè)的基本組成、結(jié)構(gòu)和節(jié)點(diǎn)等內(nèi)容。
網(wǎng)頁(yè)可以分為三大部分——HTML、CSS和JavaScript。如果把網(wǎng)頁(yè)比作一個(gè)人的話,HTML相當(dāng)于骨架,JavaScript相當(dāng)于肌肉,CSS相當(dāng)于皮膚,三者結(jié)合起來(lái)才能形成一個(gè)完善的網(wǎng)頁(yè)。下面我們分別來(lái)介紹一下這三部分的功能。
1. HTML
HTML是用來(lái)描述網(wǎng)頁(yè)的一種語(yǔ)言,其全稱叫作Hyper Text Markup Language,即超文本標(biāo)記語(yǔ)言。網(wǎng)頁(yè)包括文字、按鈕、圖片和視頻等各種復(fù)雜的元素,其基礎(chǔ)架構(gòu)就是HTML。不同類(lèi)型的文字通過(guò)不同類(lèi)型的標(biāo)簽來(lái)表示,如圖片用img標(biāo)簽表示,視頻用video標(biāo)簽表示,段落用p標(biāo)簽表示,它們之間的布局又常通過(guò)布局標(biāo)簽div嵌套組合而成,各種標(biāo)簽通過(guò)不同的排列和嵌套才形成了網(wǎng)頁(yè)的框架。
在Chrome瀏覽器中打開(kāi)百度,右擊并選擇“檢查”項(xiàng)(或按F12鍵),打開(kāi)開(kāi)發(fā)者模式,這時(shí)在Elements選項(xiàng)卡中即可看到網(wǎng)頁(yè)的源代碼,如圖2-9所示。
圖2-9 源代碼
這就是HTML,整個(gè)網(wǎng)頁(yè)就是由各種標(biāo)簽嵌套組合而成的。這些標(biāo)簽定義的節(jié)點(diǎn)元素相互嵌套和組合形成了復(fù)雜的層次關(guān)系,就形成了網(wǎng)頁(yè)的架構(gòu)。
2.CSS
HTML定義了網(wǎng)頁(yè)的結(jié)構(gòu),但是只有HTML頁(yè)面的布局并不美觀,可能只是簡(jiǎn)單的節(jié)點(diǎn)元素的排列,為了讓網(wǎng)頁(yè)看起來(lái)更好看一些,這里借助了CSS。
CSS,全稱叫作Cascading Style Sheets,即層疊樣式表。“層疊”是指當(dāng)在HTML中引用了數(shù)個(gè)樣式文件,并且樣式發(fā)生沖突時(shí),瀏覽器能依據(jù)層疊順序處理。“樣式”指網(wǎng)頁(yè)中文字大小、顏色、元素間距、排列等格式。
CSS是目前唯一的網(wǎng)頁(yè)頁(yè)面排版樣式標(biāo)準(zhǔn),有了它的幫助,頁(yè)面才會(huì)變得更為美觀。
圖2-9的右側(cè)即為CSS
就是一個(gè)CSS樣式。大括號(hào)前面是一個(gè)CSS選擇器,此選擇器的意思是首先選中id為head_wrapper且class為s-ps-islite的節(jié)點(diǎn),然后再選中其內(nèi)部的class為s-p-top的節(jié)點(diǎn)。大括號(hào)內(nèi)部寫(xiě)的就是一條條樣式規(guī)則,例如position指定了這個(gè)元素的布局方式為絕對(duì)布局,bottom指定元素的下邊距為40像素,width指定了寬度為100%占滿父元素,height則指定了元素的高度。也就是說(shuō),我們將位置、寬度、高度等樣式配置統(tǒng)一寫(xiě)成這樣的形式,然后用大括號(hào)括起來(lái),接著在開(kāi)頭再加上CSS選擇器,這就代表這個(gè)樣式對(duì)CSS選擇器選中的元素生效,元素就會(huì)根據(jù)此樣式來(lái)展示了。
在網(wǎng)頁(yè)中,一般會(huì)統(tǒng)一定義整個(gè)網(wǎng)頁(yè)的樣式規(guī)則,并寫(xiě)入CSS文件中(其后綴為css)。在HTML中,只需要用link標(biāo)簽即可引入寫(xiě)好的CSS文件,這樣整個(gè)頁(yè)面就會(huì)變得美觀、優(yōu)雅。
3. JavaScript
JavaScript,簡(jiǎn)稱JS,是一種腳本語(yǔ)言。HTML和CSS配合使用,提供給用戶的只是一種靜態(tài)信息,缺乏交互性。我們?cè)诰W(wǎng)頁(yè)里可能會(huì)看到一些交互和動(dòng)畫(huà)效果,如下載進(jìn)度條、提示框、輪播圖等,這通常就是JavaScript的功勞。它的出現(xiàn)使得用戶與信息之間不只是一種瀏覽與顯示的關(guān)系,而是實(shí)現(xiàn)了一種實(shí)時(shí)、動(dòng)態(tài)、交互的頁(yè)面功能。
JavaScript通常也是以單獨(dú)的文件形式加載的,后綴為js,在HTML中通過(guò)script標(biāo)簽即可引入,例如:
<script src="jquery-2.1.0.js"></script>
綜上所述,HTML定義了網(wǎng)頁(yè)的內(nèi)容和結(jié)構(gòu),CSS描述了網(wǎng)頁(yè)的布局,JavaScript定義了網(wǎng)頁(yè)的行為。
我們首先用例子來(lái)感受一下HTML的基本結(jié)構(gòu)。新建一個(gè)文本文件,名稱可以自取,后綴為html,內(nèi)容如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>This is a Demo</title>
</head>
<body>
<div id="container">
<div class="wrapper">
<h2 class="title">Hello World</h2>
<p class="text">Hello, this is a paragraph.</p>
</div>
</div>
</body>
</html>
這就是一個(gè)最簡(jiǎn)單的HTML實(shí)例。開(kāi)頭用DOCTYPE定義了文檔類(lèi)型,其次最外層是html標(biāo)簽,最后還有對(duì)應(yīng)的結(jié)束標(biāo)簽來(lái)表示閉合,其內(nèi)部是head標(biāo)簽和body標(biāo)簽,分別代表網(wǎng)頁(yè)頭和網(wǎng)頁(yè)體,它們也需要結(jié)束標(biāo)簽。head標(biāo)簽內(nèi)定義了一些頁(yè)面的配置和引用,如:
<meta charset="UTF-8">
它指定了網(wǎng)頁(yè)的編碼為UTF-8。
title標(biāo)簽則定義了網(wǎng)頁(yè)的標(biāo)題,會(huì)顯示在網(wǎng)頁(yè)的選項(xiàng)卡中,不會(huì)顯示在正文中。body標(biāo)簽內(nèi)則是在網(wǎng)頁(yè)正文中顯示的內(nèi)容。div標(biāo)簽定義了網(wǎng)頁(yè)中的區(qū)塊,它的id是container,這是一個(gè)非常常用的屬性,且id的內(nèi)容在網(wǎng)頁(yè)中是唯一的,我們可以通過(guò)它來(lái)獲取這個(gè)區(qū)塊。然后在此區(qū)塊內(nèi)又有一個(gè)div標(biāo)簽,它的class為wrapper,這也是一個(gè)非常常用的屬性,經(jīng)常與CSS配合使用來(lái)設(shè)定樣式。然后此區(qū)塊內(nèi)部又有一個(gè)h2標(biāo)簽,這代表一個(gè)二級(jí)標(biāo)題。另外,還有一個(gè)p標(biāo)簽,這代表一個(gè)段落。在這兩者中直接寫(xiě)入相應(yīng)的內(nèi)容即可在網(wǎng)頁(yè)中呈現(xiàn)出來(lái),它們也有各自的class屬性。
將代碼保存后,在瀏覽器中打開(kāi)該文件,可以看到如圖2-10所示的內(nèi)容。
圖2-10 運(yùn)行結(jié)果
可以看到,在選項(xiàng)卡上顯示了This is a Demo字樣,這是我們?cè)趆ead中的title里定義的文字。而網(wǎng)頁(yè)正文是body標(biāo)簽內(nèi)部定義的各個(gè)元素生成的,可以看到這里顯示了二級(jí)標(biāo)題和段落。
這個(gè)實(shí)例便是網(wǎng)頁(yè)的一般結(jié)構(gòu)。一個(gè)網(wǎng)頁(yè)的標(biāo)準(zhǔn)形式是html標(biāo)簽內(nèi)嵌套head和body標(biāo)簽,head內(nèi)定義網(wǎng)頁(yè)的配置和引用,body內(nèi)定義網(wǎng)頁(yè)的正文。
在HTML中,所有標(biāo)簽定義的內(nèi)容都是節(jié)點(diǎn),它們構(gòu)成了一個(gè)HTML DOM樹(shù)。
我們先看下什么是DOM,DOM是W3C(萬(wàn)維網(wǎng)聯(lián)盟)的標(biāo)準(zhǔn),其英文全稱Document Object Model,即文檔對(duì)象模型。它定義了訪問(wèn)HTML和XML文檔的標(biāo)準(zhǔn):
W3C文檔對(duì)象模型(DOM)是中立于平臺(tái)和語(yǔ)言的接口,它允許程序和腳本動(dòng)態(tài)地訪問(wèn)和更新文檔的內(nèi)容、結(jié)構(gòu)和樣式。
W3C DOM標(biāo)準(zhǔn)被分為3個(gè)不同的部分。
l 核心DOM: 針對(duì)任何結(jié)構(gòu)化文檔的標(biāo)準(zhǔn)模型。
l XML DOM:針對(duì)XML文檔的標(biāo)準(zhǔn)模型。
l HTML DOM:針對(duì)HTML文檔的標(biāo)準(zhǔn)模型。
根據(jù)W3C的HTML DOM標(biāo)準(zhǔn),HTML文檔中的所有內(nèi)容都是節(jié)點(diǎn)。
l 整個(gè)文檔是一個(gè)文檔節(jié)點(diǎn);
l 每個(gè)HTML元素是元素節(jié)點(diǎn);
l HTML元素內(nèi)的文本是文本節(jié)點(diǎn);
l 每個(gè)HTML屬性是屬性節(jié)點(diǎn);
注釋是注釋節(jié)點(diǎn)。
HTML DOM將HTML文檔視作樹(shù)結(jié)構(gòu),這種結(jié)構(gòu)被稱為節(jié)點(diǎn)樹(shù),如圖2-11所示。
圖2-11 節(jié)點(diǎn)樹(shù)
通過(guò)HTML DOM,樹(shù)中的所有節(jié)點(diǎn)均可通過(guò)JavaScript訪問(wèn),所有HTML節(jié)點(diǎn)元素均可被修改,也可以被創(chuàng)建或刪除。
節(jié)點(diǎn)樹(shù)中的節(jié)點(diǎn)彼此擁有層級(jí)關(guān)系。我們常用父(parent)、子(child)和兄弟(sibling)等術(shù)語(yǔ)描述這些關(guān)系。父節(jié)點(diǎn)擁有子節(jié)點(diǎn),同級(jí)的子節(jié)點(diǎn)被稱為兄弟節(jié)點(diǎn)。
在節(jié)點(diǎn)樹(shù)中,頂端節(jié)點(diǎn)稱為根(root)。除了根節(jié)點(diǎn)之外,每個(gè)節(jié)點(diǎn)都有父節(jié)點(diǎn),同時(shí)可擁有任意數(shù)量的子節(jié)點(diǎn)或兄弟節(jié)點(diǎn)。圖2-12展示了節(jié)點(diǎn)樹(shù)以及節(jié)點(diǎn)之間的關(guān)系。
圖2-12 節(jié)點(diǎn)樹(shù)及節(jié)點(diǎn)間的關(guān)系
本段參考W3SCHOOL,鏈接:http://www.w3school.com.cn/htmldom/dom_nodes.asp。
我們知道網(wǎng)頁(yè)由一個(gè)個(gè)節(jié)點(diǎn)組成,CSS選擇器會(huì)根據(jù)不同的節(jié)點(diǎn)設(shè)置不同的樣式規(guī)則,那么怎樣來(lái)定位節(jié)點(diǎn)呢?
在CSS中,我們使用CSS選擇器來(lái)定位節(jié)點(diǎn)。例如,上例中div節(jié)點(diǎn)的id為container,那么就可以表示為#container,其中#開(kāi)頭代表選擇id,其后緊跟id的名稱。另外,如果我們想選擇class為wrapper的節(jié)點(diǎn),便可以使用.wrapper,這里以點(diǎn)(.)開(kāi)頭代表選擇class,其后緊跟class的名稱。另外,還有一種選擇方式,那就是根據(jù)標(biāo)簽名篩選,例如想選擇二級(jí)標(biāo)題,直接用h2即可。這是最常用的3種表示,分別是根據(jù)id、class、標(biāo)簽名篩選,請(qǐng)牢記它們的寫(xiě)法。
另外,CSS選擇器還支持嵌套選擇,各個(gè)選擇器之間加上空格分隔開(kāi)便可以代表嵌套關(guān)系,如#container .wrapper p則代表先選擇id為container的節(jié)點(diǎn),然后選中其內(nèi)部的class為wrapper的節(jié)點(diǎn),然后再進(jìn)一步選中其內(nèi)部的p節(jié)點(diǎn)。另外,如果不加空格,則代表并列關(guān)系,如div#container .wrapper p.text代表先選擇id為container的div節(jié)點(diǎn),然后選中其內(nèi)部的class為wrapper的節(jié)點(diǎn),再進(jìn)一步選中其內(nèi)部的class為text的p節(jié)點(diǎn)。這就是CSS選擇器,其篩選功能還是非常強(qiáng)大的。
另外,CSS選擇器還有一些其他語(yǔ)法規(guī)則,具體如表2-4所示。
表2-4 CSS選擇器的其他語(yǔ)法規(guī)則
另外,還有一種比較常用的選擇器是XPath,這種選擇方式后面會(huì)詳細(xì)介紹。
本節(jié)介紹了網(wǎng)頁(yè)的基本結(jié)構(gòu)和節(jié)點(diǎn)間的關(guān)系,了解了這些內(nèi)容,我們才有更加清晰的思路去解析和提取網(wǎng)頁(yè)內(nèi)容。
*請(qǐng)認(rèn)真填寫(xiě)需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。