下代码用于采集页面时,获取网页中所有的链接,并循环输出:
$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小时内与您取得联系。