索微信公眾號(hào)了解更多: 每天看世界丫
1.link 標(biāo)簽定義是什么?
a.link 標(biāo)簽定義文檔與外部資源的關(guān)系。link 元素是空元素,它僅包含屬性。此元素只能存在于 head 部分,不過它可出現(xiàn)任 何次數(shù)。
b.link 標(biāo)簽中的 rel 屬性定義了當(dāng)前文檔與被鏈接文檔之間的關(guān)系。
c.常見的 stylesheet 指的是定義一個(gè)外部加載的樣式表。
2. link 和 @import 的區(qū)別是什么?
(1)從屬關(guān)系區(qū)別。@import 是 CSS 提供的語法規(guī)則,只有導(dǎo)入樣式表的作用;link 是 HTML 提供的標(biāo)簽,不僅可以加載 CSS 文件,還可以定義 RSS、rel 連接屬性、引入網(wǎng) 站圖標(biāo)等。
(2)加載順序區(qū)別。加載頁面時(shí),link 標(biāo)簽引入的 CSS 被同時(shí)加載;@import 引入 的 CSS 將在頁面加載完畢后被加載。
(3)兼容性區(qū)別。@import 是 CSS2.1 才有的語法,故只可在 IE5+ 才能識(shí)別;link 標(biāo) 簽作為 HTML 元素,不存在兼容性問題。
(4)DOM 可控性區(qū)別。可以通過 JS 操作 DOM ,插入 link 標(biāo)簽來改變樣式;由于 DOM 方法是基于文檔的,無法使用 @import 的方式插入樣式。
3.談?wù)勀銓?duì)瀏覽器的理解?
瀏覽器的主要功能是將用戶選擇的 web 資源呈現(xiàn)出來,它需要從服務(wù)器請(qǐng)求資源,并 將其顯示在瀏覽器窗口中,資源的格式通常是 HTML,也包括 PDF、image 及其他格式。用 戶用 URI(Uniform Resource Identifier 統(tǒng)一資源標(biāo)識(shí)符)來指定所請(qǐng)求資源的位置。HTML 和 CSS 規(guī)范中規(guī)定了瀏覽器解釋 html 文檔的方式,由 W3C 組織對(duì)這些規(guī)范 進(jìn)行維護(hù),W3C 是負(fù)責(zé)制定 web 標(biāo)準(zhǔn)的組織。但是瀏覽器廠商紛紛開發(fā)自己的擴(kuò)展,對(duì)規(guī)范的遵循并不完善,這為 web 開發(fā)者帶來 了嚴(yán)重的兼容性問題。
簡單來說瀏覽器可以分為兩部分,shell 和 內(nèi)核。其中 shell 的種類 相對(duì)比較多,內(nèi)核則比較少。shell 是指瀏覽器的外殼:例如菜單,工具欄等。主要是提供 給用戶界面操作,參數(shù)設(shè)置等等。
它是調(diào)用內(nèi)核來實(shí)現(xiàn)各種功能的。內(nèi)核才是瀏覽器的核心。內(nèi)核是基于標(biāo)記語言顯示內(nèi)容的程序或模塊。也有一些瀏覽器并不區(qū)分外殼和內(nèi)核。從Mozilla 將 Gecko 獨(dú)立出來后,才有了外殼和內(nèi)核的明確劃分。
4.談?wù)勀銓?duì)瀏覽器內(nèi)核的理解?
主要分成兩部分:渲染引擎和 JS 引擎。
渲染引擎的職責(zé)就是渲染,即在瀏覽器窗口中顯示所請(qǐng)求的內(nèi)容。
默認(rèn)情況下,渲染引 擎可以顯示 html、xml 文檔及圖片,它也可以借助插件(一種瀏覽器擴(kuò)展)顯示其他類型 數(shù)據(jù),例如使用 PDF 閱讀器插件,可以顯示 PDF 格式。
JS 引擎:解析和執(zhí)行 javascript 來實(shí)現(xiàn)網(wǎng)頁的動(dòng)態(tài)效果。最開始渲染引擎和 JS 引擎并 沒有區(qū)分的很明確,后來 JS 引擎越來越獨(dú)立,內(nèi)核就傾向于只指渲染引擎。
5.常見的瀏覽器內(nèi)核比較和區(qū)別是什么?
Trident:這種瀏覽器內(nèi)核是 IE 瀏覽器用的內(nèi)核,因?yàn)樵谠缙?IE 占有大量的市場份額, 所以這種內(nèi)核比較流行,以前有很多網(wǎng)頁也是根據(jù)這個(gè)內(nèi)核的標(biāo)準(zhǔn)來編寫的,但是實(shí)際上這 個(gè)內(nèi)核對(duì)真正的網(wǎng)頁標(biāo)準(zhǔn)支持不是很好。但是由于 IE 的高市場占有率,微軟也很長時(shí)間沒 有更新 Trident 內(nèi)核,就導(dǎo)致了 Trident 內(nèi)核和 W3C 標(biāo)準(zhǔn)脫節(jié)。還有就是 Trident 內(nèi)核的 大量 Bug 等安全問題沒有得到解決,加上一些專家學(xué)者公開自己認(rèn)為 IE 瀏覽器不安全的 觀點(diǎn),使很多用戶開始轉(zhuǎn)向其他瀏覽器。Gecko:這是 Firefox 和 Flock 所采用的內(nèi)核,這個(gè)內(nèi)核的優(yōu)點(diǎn)就是功能強(qiáng)大、豐富, 可以支持很多復(fù)雜網(wǎng)頁效果和瀏覽器擴(kuò)展接口,但是代價(jià)是也顯而易見就是要消耗很多的資 源,比如內(nèi)存。
Presto:Opera 曾經(jīng)采用的就是 Presto 內(nèi)核,Presto 內(nèi)核被稱為公認(rèn)的瀏覽網(wǎng)頁速度 最快的內(nèi)核,這得益于它在開發(fā)時(shí)的天生優(yōu)勢,在處理 JS 腳本等腳本語言時(shí),會(huì)比其他的 內(nèi)核快 3 倍左右,缺點(diǎn)就是為了達(dá)到很快的速度而丟掉了一部分網(wǎng)頁兼容性。
Webkit:Webkit 是 Safari 采用的內(nèi)核,它的優(yōu)點(diǎn)就是網(wǎng)頁瀏覽速度較快,雖然不及 Presto 但是也勝于 Gecko 和 Trident,缺點(diǎn)是對(duì)于網(wǎng)頁代碼的容錯(cuò)性不高,也就是說對(duì)網(wǎng)頁 代碼的兼容性較低,會(huì)使一些編寫不標(biāo)準(zhǔn)的網(wǎng)頁無法正確顯示。WebKit 前身是 KDE 小組 的 KHTML 引擎,可以說 WebKit 是 KHTML 的一個(gè)開源的分支。
Blink:谷歌在 Chromium Blog 上發(fā)表博客,稱將與蘋果的開源瀏覽器核心 Webkit 分 道揚(yáng)鑣,在 Chromium 項(xiàng)目中研發(fā) Blink 渲染引擎(即瀏覽器核心),內(nèi)置于 Chrome 瀏覽 器之中。其實(shí) Blink 引擎就是 Webkit 的一個(gè)分支,就像 webkit 是 KHTML 的分支一樣。Blink 引擎現(xiàn)在是谷歌公司與 Opera Software 共同研發(fā),上面提到過的,Opera 棄用了自己 的 Presto 內(nèi)核,加入 Google 陣營,跟隨谷歌一起研發(fā) Blink。
6.談?wù)劄g覽器的區(qū)別是什么?
(1) IE 瀏覽器內(nèi)核:Trident 內(nèi)核,也是俗稱的 IE 內(nèi)核;
(2)Chrome 瀏覽器內(nèi)核:統(tǒng)稱為 Chromium 內(nèi)核或 Chrome 內(nèi)核,以前是 Webkit 內(nèi)核,現(xiàn)在是 Blink 內(nèi)核;
(3) Firefox 瀏覽器內(nèi)核:Gecko 內(nèi)核,俗稱 Firefox 內(nèi)核;
(4) Safari 瀏覽器內(nèi)核:Webkit 內(nèi)核;
(5) Opera 瀏覽器內(nèi)核:最初是自己的 Presto 內(nèi)核,后來加入谷歌大軍,從 Webkit 又到了 Blink 內(nèi)核;
(6) 360 瀏覽器、獵豹瀏覽器內(nèi)核:IE + Chrome 雙內(nèi)核;
(7) 搜狗、遨游、QQ 瀏覽器內(nèi)核:Trident(兼容模式)+ Webkit(高速模式);
(8) 百度瀏覽器、世界之窗內(nèi)核:IE 內(nèi)核;
(9) 2345 瀏覽器內(nèi)核:好像以前是 IE 內(nèi)核,現(xiàn)在也是 IE + Chrome 雙內(nèi)核了;
(10)UC 瀏覽器內(nèi)核:這個(gè)眾口不一,UC 說是他們自己研發(fā)的 U3 內(nèi)核,但好像還 是基于 Webkit 和 Trident ,還有說是基于火狐內(nèi)核。
7.瀏覽器的渲染原理是什么?
(1)首先解析收到的文檔,根據(jù)文檔定義構(gòu)建一棵 DOM 樹,DOM 樹是由 DOM 元 素及屬性節(jié)點(diǎn)組成的。
(2)然后對(duì) CSS 進(jìn)行解析,生成 CSSOM 規(guī)則樹。
(3)根據(jù) DOM 樹和 CSSOM 規(guī)則樹構(gòu)建渲染樹。渲染樹的節(jié)點(diǎn)被稱為渲染對(duì)象, 渲染對(duì)象是一個(gè)包含有顏色和大小等屬性的矩形,渲染對(duì)象和 DOM 元素相對(duì)應(yīng),但這種 對(duì)應(yīng)關(guān)系不是一對(duì)一的,不可見的 DOM 元素不會(huì)被插入渲染樹。還有一些 DOM 元素對(duì)應(yīng) 幾個(gè)可見對(duì)象,它們一般是一些具有復(fù)雜結(jié)構(gòu)的元素,無法用一個(gè)矩形來描述。 (4)當(dāng)渲染對(duì)象被創(chuàng)建并添加到樹中,它們并沒有位置和大小,所以當(dāng)瀏覽器生成渲 染樹以后,就會(huì)根據(jù)渲染樹來進(jìn)行布局(也可以叫做回流)。這一階段瀏覽器要做的事情是 要弄清楚各個(gè)節(jié)點(diǎn)在頁面中的確切位置和大小。通常這一行為也被稱為“自動(dòng)重排”。
(5)布局階段結(jié)束后是繪制階段,遍歷渲染樹并調(diào)用渲染對(duì)象的 paint 方法將它們 的內(nèi)容顯示在屏幕上,繪制使用 UI 基礎(chǔ)組件。值得注意的是,這個(gè)過程是逐步完成的,為 了更好的用戶體驗(yàn),渲染引擎將會(huì)盡可能早的將內(nèi)容呈現(xiàn)到屏幕上,并不會(huì)等到所有的 html 都解析完成之后再去構(gòu)建和布局 render 樹。它是解析完一部分內(nèi)容就顯示一部分內(nèi)容,同 時(shí),可能還在通過網(wǎng)絡(luò)下載其余內(nèi)容。
8.渲染過程中遇到 JS 文件怎么處理?(瀏覽器解析過程)
JavaScript 的加載、解析與執(zhí)行會(huì)阻塞文檔的解析,也就是說,在構(gòu)建 DOM 時(shí),HTML 解析器若遇到了 JavaScript,那么它會(huì)暫停文檔的解析,將控制權(quán)移交給 JavaScript 引擎, 等 JavaScript 引擎運(yùn)行完畢,瀏覽器再從中斷的地方恢復(fù)繼續(xù)解析文檔。
也就是說,如果你想首屏渲染的越快,就越不應(yīng)該在首屏就加載 JS 文件,這也是都 建議將 script 標(biāo)簽放在 body 標(biāo)簽底部的原因。當(dāng)然在當(dāng)下,并不是說 script 標(biāo)簽必須放 在底部,因?yàn)槟憧梢越o script 標(biāo)簽添加 defer 或者 async 屬性。
9.async 和 defer 的作用是什么?有什么區(qū)別?
(1)腳本沒有 defer 或 async,瀏覽器會(huì)立即加載并執(zhí)行指定的腳本,也就是說不等 待后續(xù)載入的文檔元素,讀到就加載并執(zhí)行。
(2)defer 屬性表示延遲執(zhí)行引入的 JavaScript,即這段 JavaScript 加載時(shí) HTML 并 未停止解析,這兩個(gè)過程是并行的。當(dāng)整個(gè) document 解析完畢后再執(zhí)行腳本文件,在 DOMContentLoaded 事件觸發(fā)之前 完成。多個(gè)腳本按順序執(zhí)行。
(3)async 屬性表示異步執(zhí)行引入的 JavaScript,與 defer 的區(qū)別在于,如果已經(jīng)加 載好,就會(huì)開始執(zhí)行,也就是說它的執(zhí)行仍然會(huì)阻塞文檔的解析,只是它的加載過程不會(huì)阻 塞。多個(gè)腳本的執(zhí)行順序無法保證。
10.什么是文檔的預(yù)解析?
Webkit 和 Firefox 都做了這個(gè)優(yōu)化,當(dāng)執(zhí)行 JavaScript 腳本時(shí),另一個(gè)線程解析剩下 的文檔,并加載后面需要通過網(wǎng)絡(luò)加載的資源。這種方式可以使資源并行加載從而使整體速 度更快。需要注意的是,預(yù)解析并不改變 DOM 樹,它將這個(gè)工作留給主解析過程,自己 只解析外部資源的引用,比如外部腳本、樣式表及圖片。
、nuget 引用
Select.HtmlToPdf
2、方法
using SelectPdf;
using System.Collections.Specialized;
using System.IO;
using System.Web;
namespace BQoolCommon.Helpers.File
{
public class WebToPdf
{
public WebToPdf()
{
//SelectPdf.GlobalProperties.LicenseKey="your-license-key";
}
/// <summary>
/// 將 Html 轉(zhuǎn)成 PDF,並儲(chǔ)存成檔案
/// </summary>
/// <param name="html">html</param>
/// <param name="fileName">絕對(duì)路徑</param>
public void SaveToFileByHtml(string html, string fileName)
{
var doc=SetPdfDocument(html);
doc.Save(fileName);
}
/// <summary>
/// 傳入 Url 轉(zhuǎn)成 PDF,並儲(chǔ)存成檔案
/// </summary>
/// <param name="url">url</param>
/// <param name="fileName">絕對(duì)路徑</param>
/// <param name="httpCookies">Cookies</param>
public void SaveToFileByUrl(string url, string fileName, NameValueCollection httpCookies)
{
var doc=SetPdfDocument(url, httpCookies);
doc.Save(fileName);
}
/// <summary>
/// 將 Html 轉(zhuǎn)成 PDF,並輸出成 byte[] 格式
/// </summary>
/// <param name="html">html</param>
/// <returns></returns>
public byte[] GetFileByteByHtml(string html)
{
var doc=SetPdfDocument(html);
return doc.Save();
}
/// <summary>
/// 傳入 Url 轉(zhuǎn)成 PDF,並輸出成 byte[] 格式
/// </summary>
/// <param name="url">url</param>
/// <param name="httpCookies">Cookies</param>
/// <returns></returns>
public byte[] GetFileByteByUrl(string url, NameValueCollection httpCookies)
{
var doc=SetPdfDocument(url, httpCookies);
return doc.Save();
}
/// <summary>
/// 將 Html 轉(zhuǎn)成 PDF,並輸出成 Stream 格式
/// </summary>
/// <param name="html">html</param>
/// <returns></returns>
public Stream GetFileStreamByHtml(string html)
{
var doc=SetPdfDocument(html);
var pdfStream=new MemoryStream();
doc.Save(pdfStream);
pdfStream.Position=0;
return pdfStream;
}
/// <summary>
/// 傳入 Url 轉(zhuǎn)成 PDF,並輸出成 Stream 格式
/// </summary>
/// <param name="html">html</param>
/// <returns></returns>
public Stream GetFileStreamByUrl(string url, NameValueCollection httpCookies)
{
var doc=SetPdfDocument(url, httpCookies);
var pdfStream=new MemoryStream();
doc.Save(pdfStream);
pdfStream.Position=0;
return pdfStream;
}
private PdfDocument SetPdfDocument(string html)
{
var converter=new HtmlToPdf();
converter.Options.WebPageWidth=1200;
html=HttpUtility.HtmlDecode(html);
return converter.ConvertHtmlString(html);
}
private PdfDocument SetPdfDocument(string url, NameValueCollection httpCookies)
{
var converter=new HtmlToPdf();
converter.Options.WebPageWidth=1200;
if (httpCookies != && httpCookies.Count !=0)
{
converter.Options.HttpCookies.Add(httpCookies);
}
return converter.ConvertUrl(url);
}
}
}
近臨近開學(xué)了,大家都在忙著準(zhǔn)備各種學(xué)習(xí)的資料,準(zhǔn)備在新的學(xué)期好好學(xué)習(xí),充實(shí)自己。小編身邊的同學(xué)也是如此,最近,小編的同學(xué)小麗就遇到了一個(gè)很棘手的問題。
她想將一個(gè)網(wǎng)頁的Python學(xué)習(xí)的教程打印下來,方便自己來學(xué)習(xí),但是上千頁的教程,如果通過手動(dòng)的方式,一個(gè)一個(gè)的去轉(zhuǎn)成pdf并保存到本地,實(shí)在是麻煩的不。
這就是一個(gè)html轉(zhuǎn)pdf的問題,其實(shí)網(wǎng)上有很多不錯(cuò)的html資源,但是苦于學(xué)習(xí)起來,不方便!于是小編就跟小麗保證,這點(diǎn)小事包在我身上。今天,小編就跟分享一下如何用Python把html資料變成pdf。
如今網(wǎng)上的在線學(xué)習(xí)資料可謂是多如牛毛,為了方便講解,小編就利用python3.9.2的中文文檔作為演示的例子,來將其抓取并保存到本地,其網(wǎng)頁鏈接如下:
https://docs.python.org/zh-cn/3.9/tutorial/index.html
打開上述鏈接后,大家會(huì)在網(wǎng)頁中找到不同內(nèi)容的鏈接地址,包括了基礎(chǔ)的python字符、python語法等內(nèi)容。
在上圖中,我們需要格外關(guān)注的是紅色方格標(biāo)注的鏈接,每個(gè)鏈接都會(huì)跳轉(zhuǎn)到對(duì)應(yīng)的子網(wǎng)頁中,而在子網(wǎng)頁中,就是我們想要保存的內(nèi)容。
可以看到,上圖中,在python速覽子頁面中,包含了我們需要提取的文字內(nèi)容。所以將html內(nèi)容保存為pdf的第一步便是獲取到子頁面的鏈接。由于教程大都是固定內(nèi)容,因此對(duì)于教程的網(wǎng)頁,大都采用的是靜態(tài)頁面,在網(wǎng)頁源代碼中可以很輕松地找到子頁面的網(wǎng)頁鏈接。
對(duì)于子網(wǎng)頁的鏈接抓取,程序如下圖所示:
程序中,通過BeautifulSoup庫來解析網(wǎng)頁源代碼,然后提取所有的子頁面鏈接地址并返回,如果抓取失敗,則直接返回None。
03.html轉(zhuǎn)pdf
在得到子網(wǎng)頁的鏈接后,接下來就是將html的子網(wǎng)頁保存為pdf文件。小編使用的pdfkit庫,pdfkit庫可以將網(wǎng)頁保存為pdf文檔。首先小編來介紹一下pdfkit庫的安裝。
按照上述的操作流程,就可以安裝pdfkit庫。對(duì)于pdfkit庫的使用,常見的用法有以下三種:
上面的程序主要完成以下幾步:
首先需要指定wkhtmltopdf.exe文件的路徑;
因此,pdfkit庫只能將子網(wǎng)頁保存為單獨(dú)的pdf文檔,無法直接通過pdfkit庫將所有的子網(wǎng)頁拼接成一個(gè)完整的pdf文檔,小編通過PyPDF2庫中的PdfFileMerger類來實(shí)現(xiàn)pdf文檔的拼接。程序如下圖所示。
程序中首先將所有的html網(wǎng)頁保存為單獨(dú)的pdf文檔,然后通過PdfFileMerger類對(duì)象來實(shí)現(xiàn)pdf文檔的拼接。最后就可以得到全部的pdf內(nèi)容。最后我們通過視頻的展示,來看一下程序的效果吧。
除此之外,程序不光可以抓取python3.9的中文文檔,針對(duì)其他的在線文檔,只需要對(duì)獲取網(wǎng)頁鏈接的程序進(jìn)行修改即可抓取,例如對(duì)于Flask中文文檔的抓取,程序只需要按照下圖進(jìn)行修改,即可將Flask的在線文檔保存為PDF文檔。
學(xué)習(xí)Python其實(shí)非常有趣,也很有用。因?yàn)镻ython有大量的現(xiàn)成的庫,可以幫助我們把工作中的很多瑣碎的煩事輕松解決。小編將上述的程序稍加修改,很快就幫阿麗搞定了教程,保存為pdf發(fā)送給了她,小編與女神的關(guān)系更拉近了一步
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。