下代碼用于采集頁面時,獲取網頁中所有的鏈接,并循環輸出:
$html=file_get_contents('http://www.runoob.com');
$dom=new DOMDocument();
@$dom->loadHTML($html);
// grab all the on the page
$xpath=new DOMXPath($dom);
$hrefs=$xpath->evaluate("/html/body//a");
for ($i=0; $i < $hrefs->length; $i++) {
$href=$hrefs->item($i);
$url=$href->getAttribute('href');
echo $url.'<br />';
}
.轉換工具:PDF轉HTML
1.本地及在線軟件:
Abbyy FineReader/萬興PDF閱讀器支持直接導出HTML,Caliber則可轉換PDF至Zip格式再解壓
備選:
1.小于40M的PDF文件用Word直接導出成網頁 2.PDF閱讀器如福昕閱讀器可先轉Word后再導出網頁. 總之,如PDF閱讀器不能直轉html,可轉Word/Epub/Zip再通過解壓或者再次導出.
可以使用在線的轉換軟件,但可能會收費或有各種限制及不穩定,我在文中有推薦了部分網址.
2.定制開發工具包:
mutool 工具 : 免費開源PDF批處理工具,通過CMD命令來轉換PDF至文本/圖片/HTML網頁
poppler 命令行工具及對應的python開發包組件,也提供了命令行工具集,支持圖片單獨保存,復雜模式-C會導出一個大綱,在我體驗時出現部分格式問題,所以可以酌情參考一下再取舍.
pdf2htmlex工具: 基于mupdf / poppler基礎上改進,生成網頁效果好,但是DOM結構比較復雜,瀏覽器解析時較費資源,不太適合導入SM
說明:pdf2htmlex生成的網頁中圖片也是base64編碼保存的,所以SM中導入后也不顯示圖片
二. 操作流程: (使用mutool來作演示)
1.把PDF轉換成HTML網頁 2.導入SuperMemo學習
首選Abbyy FineReader/萬興PDF閱讀器/Mutool命令行/Word應用程序(PDF小于40M)來轉換,本文我們使用Mutool演示. 除使用Word格式(PDF小于40M直接用WORD打開,否則用福昕閱讀器先轉Word格式再用Word導出HTML).還可使用Epub或Zip格式(萬興等PDF閱讀器先轉至Epub或Caliber先轉至Zip再用解壓工具解壓. 注:Caliber貌似用的是pdf2htmlEX項目來轉換).
1.轉換PDF至HTML
mutool在之前文章已經作了介紹,本文不再進行安裝設置說明,你可以參考下文進行下載及配置
你也還可以參考官方的文檔:
步驟一: 查看mutool 工具的轉換參數(這里用的是convert命令,其實還可以用draw命令實現)
查看mutool的用法可一起使用的參數
draw命令有大部分功能和convert命令是重合的,所以它的使用參數和convert命令基本一致. 如下為draw命令日常使用的中文說明,如需更具體參考你可以看我上面放置的官網文檔鏈接:
draw命令也可實現
步驟二: 執行如下轉換命令(注意:pdf文件后是對應的PDF頁碼,如果不輸入默認轉換所有頁):
mutool convert -F html -o myfile.html -O preserve-images Y:OneDrivePDF書籍輕松Scrum之旅.pdf 1,3,44,5-20
cmd窗口執行命令
如下正確生成了html文檔,瀏覽器打開如下:
轉換帶圖片的網頁成功
步驟三: 用IE打開網頁,Ctrl+Shift+A 導入網頁并進行學習
網頁可直接導入SM進行學習
上面生成的網頁中圖片默認是用base64編碼展示的,SM軟件不支持這些圖片的導入,所以增量閱讀時圖片區域會顯示出一個叉號,所以我建議在增量閱讀到這個圖片時,如果不需要這個圖片則可以直接刪除這個叉號,如果需要則可以直接從網頁或PDF源文件中復制或截圖過來,如下圖:
SM軟件不支持base64圖片導入手動修復部分圖片的問題
以上我是用mutool工具來實現PDF至網頁生成并學習的具體步驟,因該命令行工具現版本所支持的html導出用的是base64編碼來存儲圖片,所以如上我會增加一步手工取圖的操作(可以用簡單的腳本處理下網頁,把base64圖片文件化,然后替換圖片鏈接,具體可以參考我文末的方案).
簡單較小的PDF文件,Word程序來導出也可以,不然則可用其它備選工具,如Abbyy FineReader或萬興PDF閱讀器(PDF轉換成HTML或轉成Epub再解壓)來實現PDF到HTML網頁的轉換,這兩個工具生成的網頁圖片是可以直接導入的,但注意,這兩個軟件也不是完美的. 比如: 軟件收費/文本識別率有時會比mutool更低 / 排版錯亂 /轉換速度慢/轉換時消耗資源高/不方便需求定制等.
====總結: PDF轉換至HTML網頁的方案===
1.ABBYY FineReader / 萬興PDF閱讀器 軟件本身支持轉換文本圖形分離的網頁,只不過要收費,另外也可以直接Word程序(PDF大小限制),福昕->Word,萬興->Epub,Caliber->Zip等間接方式.
2.在線的轉換工具,WPS在線轉換/永中在線轉換等在線轉換工具,會有各種限制及收費,不穩定等問題, 也存在一定隱私問題,無法自定規則及不方便批處理.如下放置幾個免費的在線轉換網址:
3.mutool 命令行工具及 mupdf api 庫 / poppler / 基于前兩個軟件的pdf2htmlEX 等轉換工具
mutool使用簡單,只不過生成網頁中圖片是用base64編碼的,上面我建議是這樣操作: 導入進SM軟件來學習時,顯示叉號但不需要的圖片可直接刪除,需要的圖片直接從網頁拷貝源圖片到SM軟件即可.如果你一定要導入圖片在SM學習可以按我文末的方法簡單處理一下生成的HTML網頁.
poppler自帶了一套工具集,可以實現PDF轉換成文本/圖片/網頁. 使用工具pdf2html可以生成文本及圖片分離的網頁,但實驗中會有一小部分網頁格式上會有亂的情況,所以自己綜合看下效果.
pdf2htmlEX 生成網頁效果最好,但網頁文件較大/DOM結構較復雜/網頁解析消耗資源,圖片也是返回base64,如果是要導入SM中進行增量,還是不建議了,直接用瀏覽器打開體驗還是很不錯的.
Mutool免費開源,提供了命令行工具套件及pymupdf編程包,社區活躍,迭代的速度很快.支持多線程,網頁轉換速度相當快.方便自己定制處理,所以比較推薦.
如下: 我們會發現mupdf官網版本修復/更新非常快,很多軟件現在沒有的功能相信很快會出現:
代碼提交更新數據
--------2021-01-31 增加如下--------:
針對mutool導出html時圖片默認為base64編碼的問題.網上也有人提出過問題,官方回答是建議自己單獨寫代碼來處理一下,把base64的圖片保存至本地并用本地鏈接替換回原來的img鏈接.
# 方式一 : 對mutool生成的HTML網頁直接解析,解碼出圖片并替換鏈接... image = json.loads(pg.getText('json'))['blocks'][0]['image'] img = Image.open(io.BytesIO(base64.b64decode(image))) #fitz.Pixmap(doc, xref)
# 方式二: 直接使用Mupdf的API自已生成HTML,使用dict來取圖片及文本...doc = fitz.open(file_path)for page in doc: page.getText("dict")
我是一只熱愛學習的小胖子,如果你也熱愛學習,并且對SuperMemo感興趣,歡迎轉發和評論!
. 增強HttpServletResponse對象
1. 實現一個增強的HttpServletResponse類,需要繼承javax.servlet.http.HttpServletRequestWrapper類,通過重寫自己需要增強的方法來實現(這種模式就叫做裝飾者模式),使用該增強類在加上過濾器就可以實現無編碼轉換處理代碼。
public class MyRequest extends HttpServletRequestWrapper{ private HttpServletRequest req; public MyRequest(HttpServletRequest request) { super(request); req=request; } @Override public String getParameter(String name) { //解決編碼問題,無論是post還是get請求,都不需要在業務代碼中對編碼再處理 String method=req.getMethod(); if("get".equalsIgnoreCase(method)){ try { String str=req.getParameter(name); byte[] b=str.getBytes("iso8859-1"); String newStr=new String(b, "utf-8"); return newStr; } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } }else if("post".equalsIgnoreCase(method)){ try { req.setCharacterEncoding("utf-8"); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //絕對不能刪除此行代碼,因為此行代碼返回的就是編碼之后的數據 return super.getParameter(name); } }
在過濾器中應用
public class FilterTest4 implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException {} @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //生成增強的HttpServletRequest對象 HttpServletRequest req=(HttpServletRequest) request; MyRequest myReq=new MyRequest(req); //將增強的HttpServletRequest對象傳入過濾器執行鏈中,在后面傳入的request對象都會是增強的HttpServletRequest對象 chain.doFilter(myReq, response); } @Override public void destroy() {} }
2. 文件上傳原理過程
1. JavaWeb中實現文件上傳:
<html> <head> <title>My JSP 'upload.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> </head> <body> <form action="" method="post" enctype="multipart/form-data"> <input type="text" name="name"> 請選擇文件:<input type="file" name="upload"> <input type="submit" value="上傳"> </form> </body> </html>
import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; public class UploadServlet extends HttpServlet{ @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { /** * 1. 創建磁盤文件項工廠類 DiskFileItemFactory * 2. 創建核心解析Request類 ServletFileUpload * 3. 開始解析Request對象中的數據,并返回一個List集合 * 4. List中包含表單中提交的內容 * 5. 遍歷集合,獲取內容 */ DiskFileItemFactory fac=new DiskFileItemFactory(); ServletFileUpload upload=new ServletFileUpload(fac); upload.setHeaderEncoding("utf-8");//防止中文的文件名亂碼 try { List<FileItem> fileItems=upload.parseRequest(req); for(FileItem item:fileItems){ //有可能是普通文本項,比如<input type="text">標簽提交上來的字符串 //也有可能是<input type="submit" value="上傳">上傳的文件 //文件項與普通項有不同的API來處理 //首先判斷是普通文本項還是文件項, if(item.isFormField()){ //true表示普通文本項 //獲取文本項的name屬性值 String name=item.getFieldName(); //獲取對應的文本 String value=item.getString("utf-8");//防止中文亂碼 System.out.println(name+":"+value); }else{ //false表示文件項 //先獲取文件名稱 String name=item.getName(); //獲取文件項的輸入流 InputStream in=item.getInputStream(); //獲取服務器端文件存儲的目標磁盤路徑 String path=getServletContext().getRealPath("/upload"); System.out.println(path); //獲取輸出流,輸出到本地文件中 OutputStream out=new FileOutputStream(path+"/"+name); //寫入數據 int len=0; byte[] b=new byte[1024]; while((len=in.read(b))!=-1){ out.write(b,0,len); } in.close(); out.close(); } } } catch (FileUploadException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
注意:在文件上傳時,會將form表單的屬性enctype屬性值為"multipart/form-data",當提交到服務端后,無法使用 req.getParameter(name) 方法來獲取到內容,只有通過上面的方法來獲取文本項。
2. 文件上傳相關核心類:
//改進上面的文件上傳代碼,添加一個臨時文件 public class UploadServlet extends HttpServlet{ @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { DiskFileItemFactory fac=new DiskFileItemFactory(); fac.setSizeThreshold(1024*1024);//設置緩沖區為1mb //設置臨時文件的本地磁盤存儲路徑 File repository=new File(getServletContext().getRealPath("/temp")); fac.setRepository(repository); ServletFileUpload upload=new ServletFileUpload(fac); upload.setHeaderEncoding("utf-8");//防止中文的文件名亂碼 try { List<FileItem> fileItems=upload.parseRequest(req); for(FileItem item:fileItems){ if(item.isFormField()){ String name=item.getFieldName(); String value=item.getString(); String value=item.getString("utf-8");//防止中文亂碼 System.out.println(name+":"+value); }else{ String name=item.getName(); InputStream in=item.getInputStream(); String path=getServletContext().getRealPath("/upload"); System.out.println(path); OutputStream out=new FileOutputStream(path+"/"+name); int len=0; byte[] b=new byte[1024]; while((len=in.read(b))!=-1){ out.write(b,0,len); } in.close(); out.close(); } } } catch (FileUploadException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
3. 實現多文件上傳(需要js技術):主要是更改jsp頁面,通過js代碼來添加多個文件進行上傳,服務器代碼無需更改
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" contentType="text/html; charset=utf-8"%> <% String path=request.getContextPath(); String basePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'upload.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> </head> <body> <script type="text/javascript"> function run(){ var div=document.getElementById("divId"); div.innerHTML+="<div><input type='file' name='upload'><input type='button' value='刪除' onclick='del(this)'></div>" } function del(presentNode){ var div=document.getElementById("divId"); div.removeChild(presentNode.parentNode); } </script> <div> 多文件上傳<br/> <form action="/Servlet/upload" method="post" enctype="multipart/form-data"> <input type="button" value="添加" onclick="run()"><br/> <div id="divId"> </div> <input type="submit" value="上傳"> </form> </div> </body> </html>
4. 關于文件上傳的一些問題:
3. 文件下載
1. 傳統文件下載方式有超鏈接下載或者后臺程序下載兩種方式。通過超鏈接下載時,如果瀏覽器可以解析,那么就會直接打開,如果不能解析,就會彈出下載框;而后臺程序下載就必須通過兩個響應頭和一個文件的輸入流。
2. 后臺程序下載:
*請認真填寫需求信息,我們會在24小時內與您取得聯系。