要使用的是wkhtmltopdf的Python封裝——pdfkit
安裝
1. Install python-pdfkit:
$ pip install pdfkit
2. Install wkhtmltopdf:
$ sudo apt-get install wkhtmltopdf
sudo yum intsall wkhtmltopdf
brew install Caskroom/cask/wkhtmltopdf
使用
一個簡單的例子:
import pdfkit
pdfkit.from_url('http://google.com', 'out.pdf')
pdfkit.from_file('test.html', 'out.pdf')
pdfkit.from_string('Hello!', 'out.pdf')
你也可以傳遞一個url或者文件名列表:
pdfkit.from_url(['google.com', 'yandex.ru', 'engadget.com'], 'out.pdf')
pdfkit.from_file(['file1.html', 'file2.html'], 'out.pdf')
也可以傳遞一個打開的文件:
with open('file.html') as f:
pdfkit.from_file(f, 'out.pdf')
如果你想對生成的PDF作進一步處理, 你可以將其讀取到一個變量中:
# 設置輸出文件為False,將結果賦給一個變量
pdf = pdfkit.from_url('http://google.com', False)
你可以制定所有的 wkhtmltopdf 選項 http://wkhtmltopdf.org/usage/wkhtmltopdf.txt. 你可以移除選項名字前面的 '--' .如果選項沒有值, 使用None, False or * 作為字典值:
options = {
'page-size': 'Letter',
'margin-top': '0.75in',
'margin-right': '0.75in',
'margin-bottom': '0.75in',
'margin-left': '0.75in',
'encoding': "UTF-8",
'no-outline': None
}
pdfkit.from_url('http://google.com', 'out.pdf', options=options)
默認情況下, PDFKit 將會顯示所有的 wkhtmltopdf 輸出. 如果你不想看到這些信息,你需要傳遞一個 quiet 選項:
options = {
'quiet': ''
}
pdfkit.from_url('google.com', 'out.pdf', options=options)
由于wkhtmltopdf的命令語法 , TOC 和 Cover 選項必須分開指定:
toc = {
'xsl-style-sheet': 'toc.xsl'
}
cover = 'cover.html'
pdfkit.from_file('file.html', options=options, toc=toc, cover=cover)
當你轉換文件、或字符串的時候,你可以通過css選項指定擴展的 CSS 文件。
# 單個 CSS 文件
css = 'example.css'
pdfkit.from_file('file.html', options=options, css=css)
# Multiple CSS files
css = ['example.css', 'example2.css']
pdfkit.from_file('file.html', options=options, css=css)
你也可以通過你的HTML中的meta tags傳遞任意選項:
body = """
<html>
<head>
<meta name="pdfkit-page-size" content="Legal"/>
<meta name="pdfkit-orientation" content="Landscape"/>
</head>
Hello World!
</html>
"""
pdfkit.from_string(body, 'out.pdf') #with --page-size=Legal and --orientation=Landscape
配置
每個API調用都有一個可選的參數。這應該是pdfkit.configuration()API 調用的一個實例. 采用configuration 選項作為初始化參數。可用的選項有:
示例 :針對wkhtmltopdf不在系統路徑中(不在$PATH里面)
PATH里面):
config = pdfkit.configuration(wkhtmltopdf='/opt/bin/wkhtmltopdf'))
pdfkit.from_string(html_string, output_file, configuration=config)
問題
IOError:'No wkhtmltopdf executable found':
確保 wkhtmltopdf 在你的系統路徑中(PATH), 會通過 configuration進行了配置 (詳情看上文描述)。 在Windows系統中使用where wkhtmltopdf命令 或 在 linux系統中使用 which wkhtmltopdf 會返回 wkhtmltopdf二進制可執行文件所在的確切位置.
如果出現這個錯誤意味著 PDFKit不能處理一個輸入。你可以嘗試直接在錯誤信息后面直接運行一個命令來查看是什么導致了這個錯誤 (某些版本的 wkhtmltopdf會因為段錯誤導致處理失敗)
確保兩項:
1)、你的系統中有中文字體
2)、在html中加入
下面是我隨便寫的一個HTML表格:
<html>
<head><meta charset="UTF-8"></head>
<body>
<table width="400" border="1">
<tr>
<th align="left">Item....</th>
<th align="right">1</th>
</tr>
<tr>
<td align="left">衣服</td>
<td align="right">1.10</td>
</tr>
<tr>
<td align="left">化妝品</td>
<td align="right">.00</td>
</tr>
<tr>
<td align="left">食物</td>
<td align="right">0.40</td>
</tr>
<tr>
<th align="left">tOTAL</th>
<th align="right">01.50</th>
</tr>
</table>
</body>
</html>
下面是生成的PDF截圖
近臨近開學了,大家都在忙著準備各種學習的資料,準備在新的學期好好學習,充實自己。小編身邊的同學也是如此,最近,小編的同學小麗就遇到了一個很棘手的問題。
她想將一個網頁的Python學習的教程打印下來,方便自己來學習,但是上千頁的教程,如果通過手動的方式,一個一個的去轉成pdf并保存到本地,實在是麻煩的不。
這就是一個html轉pdf的問題,其實網上有很多不錯的html資源,但是苦于學習起來,不方便!于是小編就跟小麗保證,這點小事包在我身上。今天,小編就跟分享一下如何用Python把html資料變成pdf。
如今網上的在線學習資料可謂是多如牛毛,為了方便講解,小編就利用python3.9.2的中文文檔作為演示的例子,來將其抓取并保存到本地,其網頁鏈接如下:
https://docs.python.org/zh-cn/3.9/tutorial/index.html
打開上述鏈接后,大家會在網頁中找到不同內容的鏈接地址,包括了基礎的python字符、python語法等內容。
在上圖中,我們需要格外關注的是紅色方格標注的鏈接,每個鏈接都會跳轉到對應的子網頁中,而在子網頁中,就是我們想要保存的內容。
可以看到,上圖中,在python速覽子頁面中,包含了我們需要提取的文字內容。所以將html內容保存為pdf的第一步便是獲取到子頁面的鏈接。由于教程大都是固定內容,因此對于教程的網頁,大都采用的是靜態頁面,在網頁源代碼中可以很輕松地找到子頁面的網頁鏈接。
對于子網頁的鏈接抓取,程序如下圖所示:
程序中,通過BeautifulSoup庫來解析網頁源代碼,然后提取所有的子頁面鏈接地址并返回,如果抓取失敗,則直接返回None。
03.html轉pdf
在得到子網頁的鏈接后,接下來就是將html的子網頁保存為pdf文件。小編使用的pdfkit庫,pdfkit庫可以將網頁保存為pdf文檔。首先小編來介紹一下pdfkit庫的安裝。
按照上述的操作流程,就可以安裝pdfkit庫。對于pdfkit庫的使用,常見的用法有以下三種:
上面的程序主要完成以下幾步:
首先需要指定wkhtmltopdf.exe文件的路徑;
因此,pdfkit庫只能將子網頁保存為單獨的pdf文檔,無法直接通過pdfkit庫將所有的子網頁拼接成一個完整的pdf文檔,小編通過PyPDF2庫中的PdfFileMerger類來實現pdf文檔的拼接。程序如下圖所示。
程序中首先將所有的html網頁保存為單獨的pdf文檔,然后通過PdfFileMerger類對象來實現pdf文檔的拼接。最后就可以得到全部的pdf內容。最后我們通過視頻的展示,來看一下程序的效果吧。
除此之外,程序不光可以抓取python3.9的中文文檔,針對其他的在線文檔,只需要對獲取網頁鏈接的程序進行修改即可抓取,例如對于Flask中文文檔的抓取,程序只需要按照下圖進行修改,即可將Flask的在線文檔保存為PDF文檔。
學習Python其實非常有趣,也很有用。因為Python有大量的現成的庫,可以幫助我們把工作中的很多瑣碎的煩事輕松解決。小編將上述的程序稍加修改,很快就幫阿麗搞定了教程,保存為pdf發送給了她,小編與女神的關系更拉近了一步
我們看一下通過Python Selenium WebDriver執行JavaScript語句的幾種不同方法。
在本教程中,讓我們分析Selenium WebDriver中使用最少但功能最強大的功能。是的,我將討論JavaScript執行器,并向您展示通過Python Selenium WebDriver執行JavaScript語句的幾種不同方法。
可能會發生這種情況,在某些實時項目中,Selenium WebDriver無法對特定的Web元素執行操作。例如,由于WebDriver模擬最終用戶交互,因此很自然地會拒絕單擊最終用戶看不到的元素(有時即使Web元素在頁面上可見,也會發生這種情況)。可能有其他幾個類似的原因或情況。
在這些情況下,我們可以依靠JavaScript來單擊或對該Web元素執行操作,并且可以通過WebDriver執行這些JavaScript語句。
您可以使用JavaScript執行WebElement界面所做的所有操作。
什么是JavaScript?
JavaScript是一種腳本語言,它在客戶端運行,即在瀏覽器上運行,并且當您瀏覽網頁時會做一些神奇的事情。有關更多詳細信息,請在DZone上搜索關鍵字“JavaScript”。
我們如何在WebDriver中使用JavaScript?
Python Selenium WebDriver提供了一個內置方法:
driver.execute_script("some javascript code here");
我們可以通過兩種方式在瀏覽器中執行JavaScript。
方法1:在文檔根級別執行JavaScript
在這種情況下,我們使用JavaScript提供的方法捕獲我們想要使用的元素,然后在其上聲明一些操作并使用WebDriver執行此JavaScript。
例:
javaScript = "document.getElementsByName('username')[0].click();"
driver.execute_script(javaScript)
我們在這里做什么?
第1步:我們正在使用JavaScript檢查并通過屬性“名稱”獲取元素。(另外,可以使用'id'和'class'屬性。)
第2步:使用JavaScript聲明并對元素執行單擊操作。
第3步:調用execute_script()方法并將我們創建的JavaScript作為字符串值傳遞。
請注意 上面[0] 的 getElementsByName('username')[0] 聲明。JavaScript函數 getElementsByName , getElementsByClassName 等返回所有匹配的元件的陣列。在我們的例子中,我們需要對可以通過的第一個匹配元素進行操作 index [0] 。如果您知道自己在做什么,即,如果您知道要操作的元素的索引,則可以直接使用索引,例如 getElementsByName('username')[2] 。
但是,如果您使用的是JavaScript函數' getElementById ',則不需要使用任何索引,因為它只返回一個元素('id'應該是唯一的)。
執行時,WebDriver會將JavaScript語句注入瀏覽器,腳本將執行該任務。在我們的示例中,它對目標元素執行單擊操作。此JavaScript具有自己的命名空間,不會干擾實際網頁中的JavaScript。
方法2:在元素級別執行JavaScript
在這種情況下,我們使用WebDriver捕獲我們想要使用的元素,然后使用JavaScript在其上聲明一些操作,并通過將web元素作為參數傳遞給JavaScript來使用WebDriver執行此JavaScript。
這令人困惑嗎?讓我們分解吧。
例如:
userName = driver.find_element_by_xpath("http://button[@name='username']")
driver.execute_script("arguments[0].click();", userName)
我們在這里做什么?
第1步:使用WebDriver提供的方法檢查和捕獲元素,例如'find_element_by_xpath ':
userName = driver.find_element_by_xpath("http://button[@name='username']")
第2步:使用JavaScript聲明并對元素執行單擊操作:
arguments[0].click()
第3步:execute_script() 使用我們創建的JavaScript語句作為字符串值調用 方法,并使用WebDriver作為參數捕獲Web元素:
driver.execute_script("arguments[0].click();", userName)
上面兩行代碼可以縮短為下面的格式,我們使用WebDriver找到一個元素,聲明一些JavaScript函數,并使用WebDriver執行JavaScript。
driver.execute_script("arguments[0].click();",
driver.find_element_by_xpath("http://button[@name='username']"))
更頻繁面臨的另一個問題是需要滾動到網頁的底部。您可以在一行代碼中執行此操作:
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
此外,您的語句中可以有多個JavaScript操作。
例如:
userName = driver.find_element_by_xpath("http://button[@name='username']")
password = driver.find_element_by_xpath("http://button[@name='password']")
driver.execute_script("arguments[0].click();arguments[1].click();", userName, password)
在這種情況下,web元素的順序的使用很重要。訪問 index 與 [0] 一個JavaScript語句中的任何位置將檢索傳遞的第一個網頁元素。
driver.execute_script("arguments[1].click();arguments[0].click();", userName, password)
如何返回值
JavaScript執行程序的另一個重要方面是它可用于從Web元素中獲取值。這意味著該 execute_script() 方法可以返回值。
例如:
print driver.execute_script('return document.getElementById("fsr").innerText')
請注意,如果您想要JavaScript代碼返回的內容,則需要使用return。此外,可以使用Selenium定位元素并將其傳遞到腳本中。
什么元素找不到會發生什么?
當JavaScript找不到要操作的元素時,它會拋出帶有相應錯誤消息的WebDriver異常。
場景1:我們正在嘗試使用' print driver.execute_script('return document.getElementById("fsr").innerText') ' 來讀取屬性, 但網頁中沒有這樣的元素。我們在異常跟蹤中收到以下消息:
selenium.common.exceptions.WebDriverException: Message: unknown error: Cannot read property 'innerText' of null
場景2:我們試圖在JavaScript中使用無效的操作或錯誤函數名稱,例如' print driver.execute_script('document.getElementById("fsr").clic();') '。(注意click() 方法名稱中的拼寫錯誤 。)
selenium.common.exceptions.WebDriverException: Message: unknown error: document.getElementById(...).clic is not a function
摘要
以下是可以使用JavaScript的一些潛在操作的摘要。
使用Selenium處理DOM時,JavaScript的基本知識有很大幫助。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。