数据抓取的问题,涉及到1 用URLConnection 读取页面信息,用httpclient也行2 用Pattern 解析页面并拿到你要的信息3 显示数据4 存入数据库这个是一个综合的考试,涉及的知识面比较广。1 我这里只给出关键的部分,使用java程序实现,而不是JSP的代码。移植工作请自行完成。2 我使用自己的数据库连接,请替换为应用服务器提供的数据源为好3 代码分三部分,数据库结构,POJO类和应用程序,当然还有一个辅助类,也是我自己写的
4 欢迎光临老紫竹的JAVA世纪网 http://www.java2000.net, 呵呵,广告放里面了一、数据库结构 AmazonGoods.sql 使用的是MySQL的数据库
[java]
view plain
copy
print
?
1. -- ----------------------------
2. -- Table structure for
3. -- ----------------------------
4. CREATE TABLE `amazongoods` (
5. int(11) NOT NULL AUTO_INCREMENT,
6. 10,0) NOT NULL,
7. 10,0) NOT NULL,
8. `Seller` text NOT NULL,
9. PRIMARY KEY (`id`)
10. ) ENGINE=InnoDB AUTO_INCREMENT=11
-- ------------------------------ Table structure for amazongoods-- ----------------------------CREATE TABLE `amazongoods` ( `id` int(11) NOT NULL AUTO_INCREMENT, `price` decimal(10,0) NOT NULL, `shipping` decimal(10,0) NOT NULL, `Seller` text NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
二、POJO类 AmazonGoods.java
[java]
view plain
copy
print
?
1. package
2. import
3. /**
4. * 某一行的商品数据
5. *
6. * @author 老紫竹的家(laozizhu.com)
7. *
8. */
9. class
10. public long
11. return
12. }
13. public void setId(long
14. this.id = id;
15. }
16. public
17. return
18. }
19. public void
20. this.price = price;
21. }
22. public
23. return
24. }
25. public void
26. this.shipping = shipping;
27. }
28. public
29. return
30. }
31. public void
32. this.seller = seller;
33. }
34. // 序列号,主键
35. private long
36. // 价格
37. private
38. // 运费
39. private
40. // 商家信息
41. private
42. }
package com.laozizhu.test.amazon;import java.math.BigDecimal;/** * 某一行的商品数据 * * @author 老紫竹的家(laozizhu.com) * */class AmazonGoods { public long getId() { return id; } public void setId(long id) { this.id = id; } public BigDecimal getPrice() { return price; } public void setPrice(BigDecimal price) { this.price = price; } public BigDecimal getShipping() { return shipping; } public void setShipping(BigDecimal shipping) { this.shipping = shipping; } public String getSeller() { return seller; } public void setSeller(String seller) { this.seller = seller; } // 序列号,主键 private long id; // 价格 private BigDecimal price; // 运费 private BigDecimal shipping; // 商家信息 private String seller;}
三、应用类
[java]
view plain
copy
print
?
1. package
2. import
3. import
4. import
5. import
6. import
7. import
8. import
9. import
10. import
11. import
12. public class
13. /**
14. * @param args
15. */
16. public static void
17. // 我这里需要设置代理,如果你能直接访问互联网,则无需这段代码了
18. initProxy();
19. // 读取页面数据
20. "http://www.amazon.com/gp/offer-listing/B0012J52OC/", "ISO-8859-1");
21. // 解析页面,拿到商品信息
22. List<AmazonGoods> list = parse(str);
23. // 生成HTML表格
24. buildTable(list);
25. // 存入数据库
26. saveToMySQL(list);
27. }
28. /**
29. * 简单的代理服务器,无需密码认证
30. */
31. private static void
32. Properties prop = System.getProperties();
33. // prop.put("proxySet", "true");
34. // 设置http访问要使用的代理服务器的地址
35. "http.proxyHost", "10.60.8.20");
36. // 设置http访问要使用的代理服务器的端口
37. "http.proxyPort", "8080");
38. }
39. // 注意,美元符号要转义
40. // 因为报价都包含小数点,所以用数字+小数点+2位小数即可
41. // 商家信息包含了对应的标签
42. static
43. "<span class=/"price/">//$([//d]+//.[//d]{2})</span>.*?(<ul class=/"sellerInformation/">.+?</ul>)", Pattern.DOTALL);
44. // 运费
45. // <span class="price_shipping">+ $6.04</span>
46. static
47. "<span class=/"price_shipping/">//+ //$([//d]+//.[//d]{2})</span>", Pattern.DOTALL);
48. /**
49. * 解析页面,获得商品列表
50. *
51. * @param page
52. * 页面
53. * @return 商品列表
54. */
55. private static
56. // 首先,把商品分成多个字符串片段
57. // 分割符就是表格里的内容了。这个得查看HTML源代码才能找到合适的
58. "<tbody class=/"result/">");
59. // 构造结果
60. // 默认长度为片段的长度,呵呵
61. new
62. null;
63. // 循环解析每个商品片段
64. for
65. // 注意,不是每个商品都有运费,所以正则最好不要写一个
66. // 当然,你愿意弄复杂了也行,我个人不推荐这么做
67. Matcher m = pPrice.matcher(str);
68. if
69. new
70. new BigDecimal(m.group(1)));
71. // 这里面包含了HTML的信息,包括Javascript内容,不过比较难删除
72. // 因为有些页面文字是用js显示的,还是保留的比较好
73. 2));
74. // 查找运费
75. m = pShipping.matcher(str);
76. if
77. new BigDecimal(m.group(1)));
78. }
79. // 将商品加入列表
80. list.add(goods);
81. else
82. // 没有找到价格,则这部分不包含商品信息,无需继续
83. continue;
84. }
85. }
86. return
87. }
88. private static
89. new StringBuilder("<table>");
90. "<tr><th>价格</th><th>运费</th><th>商家信息</th></tr>");
91. for
92. "<tr><th>" + goods.getPrice() + "</th><th>" + goods.getShipping() + "</th><th>"
93. "</th></tr>");
94. }
95. "</table>");
96. return
97. }
98. private static void
99. // 这里就用最原始的方法获得数据库连接了。
100. // 数据库结构请参考AmazonGoods.sql
101. // 使用test的数据库
102. null;
103. null;
104. "jdbc:mysql://localhost:3306/";
105. "test";
106. "com.mysql.jdbc.Driver";
107. "test";
108. "test";
109. new BigDecimal("0");
110. try
111. Class.forName(driver);
112. con = DriverManager.getConnection(url + db, user, pass);
113. "insert into AmazonGoods (price,shipping,seller) values(?,?,?)");
114. for
115. 1, goods.getPrice());
116. 2, goods.getShipping()==null?ZERO:goods.getShipping());
117. 3, goods.getSeller());
118. if (st.executeUpdate() <= 0) {
119. throw new Exception("保存数据错误!");
120. }
121. st.clearParameters();
122. }
123. catch
124. ex.printStackTrace();
125. finally
126. if (st != null) {
127. try
128. st.close();
129. catch
130. }
131. }
132. if (con != null) {
133. try
134. con.close();
135. catch
136. }
137. }
138. }
139. }
140. }
package com.laozizhu.test.amazon;import java.math.BigDecimal;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.util.ArrayList;import java.util.List;import java.util.Properties;import java.util.regex.Matcher;import java.util.regex.Pattern;import com.laozizhu.tools.PageService;public class AmazonFetch { /** * @param args */ public static void main(String[] args) { // 我这里需要设置代理,如果你能直接访问互联网,则无需这段代码了 initProxy(); // 读取页面数据 String str = PageService.getPage("http://www.amazon.com/gp/offer-listing/B0012J52OC/", "ISO-8859-1"); // 解析页面,拿到商品信息 List<AmazonGoods> list = parse(str); // 生成HTML表格 buildTable(list); // 存入数据库 saveToMySQL(list); } /** * 简单的代理服务器,无需密码认证 */ private static void initProxy() { Properties prop = System.getProperties(); // prop.put("proxySet", "true"); // 设置http访问要使用的代理服务器的地址 prop.setProperty("http.proxyHost", "10.60.8.20"); // 设置http访问要使用的代理服务器的端口 prop.setProperty("http.proxyPort", "8080"); } // 注意,美元符号要转义 // 因为报价都包含小数点,所以用数字+小数点+2位小数即可 // 商家信息包含了对应的标签 static Pattern pPrice = Pattern.compile( "<span class=/"price/">//$([//d]+//.[//d]{2})</span>.*?(<ul class=/"sellerInformation/">.+?</ul>)", Pattern.DOTALL); // 运费 // <span class="price_shipping">+ $6.04</span> static Pattern pShipping = Pattern .compile("<span class=/"price_shipping/">//+ //$([//d]+//.[//d]{2})</span>", Pattern.DOTALL); /** * 解析页面,获得商品列表 * * @param page * 页面 * @return 商品列表 */ private static List<AmazonGoods> parse(String page) { // 首先,把商品分成多个字符串片段 // 分割符就是表格里的内容了。这个得查看HTML源代码才能找到合适的 String[] strs = page.split("<tbody class=/"result/">"); // 构造结果 // 默认长度为片段的长度,呵呵 List<AmazonGoods> list = new ArrayList<AmazonGoods>(strs.length); AmazonGoods goods = null; // 循环解析每个商品片段 for (String str : strs) { // 注意,不是每个商品都有运费,所以正则最好不要写一个 // 当然,你愿意弄复杂了也行,我个人不推荐这么做 Matcher m = pPrice.matcher(str); if (m.find()) { goods = new AmazonGoods(); goods.setPrice(new BigDecimal(m.group(1))); // 这里面包含了HTML的信息,包括Javascript内容,不过比较难删除 // 因为有些页面文字是用js显示的,还是保留的比较好 goods.setSeller(m.group(2)); // 查找运费 m = pShipping.matcher(str); if (m.find()) { goods.setShipping(new BigDecimal(m.group(1))); } // 将商品加入列表 list.add(goods); } else { // 没有找到价格,则这部分不包含商品信息,无需继续 continue; } } return list; } private static String buildTable(List<AmazonGoods> list) { StringBuilder b = new StringBuilder("<table>"); b.append("<tr><th>价格</th><th>运费</th><th>商家信息</th></tr>"); for (AmazonGoods goods : list) { b.append("<tr><th>" + goods.getPrice() + "</th><th>" + goods.getShipping() + "</th><th>" + goods.getSeller() + "</th></tr>"); } b.append("</table>"); return b.toString(); } private static void saveToMySQL(List<AmazonGoods> list) { // 这里就用最原始的方法获得数据库连接了。 // 数据库结构请参考AmazonGoods.sql // 使用test的数据库 Connection con = null; PreparedStatement st = null; String url = "jdbc:mysql://localhost:3306/"; String db = "test"; String driver = "com.mysql.jdbc.Driver"; String user = "test"; String pass = "test"; BigDecimal ZERO = new BigDecimal("0"); try { Class.forName(driver); con = DriverManager.getConnection(url + db, user, pass); st = con.prepareStatement("insert into AmazonGoods (price,shipping,seller) values(?,?,?)"); for (AmazonGoods goods : list) { st.setBigDecimal(1, goods.getPrice()); st.setBigDecimal(2, goods.getShipping()==null?ZERO:goods.getShipping()); st.setString(3, goods.getSeller()); if (st.executeUpdate() <= 0) { throw new Exception("保存数据错误!"); } st.clearParameters(); } } catch (Exception ex) { ex.printStackTrace(); } finally { if (st != null) { try { st.close(); } catch (Exception ex) { } } if (con != null) { try { con.close(); } catch (Exception ex) { } } } }}
四、辅助类,PageService.java
[java]
view plain
copy
print
?
1. package
2. import
3. import
4. import
5. import
6. import
7. import
8. import
9. import
10. import
11. /**
12. * 读取URL的文本工具
13. *
14. * @author 赵学庆 www.java2000.net
15. */
16. public class
17. private static final String BR = "/r/n";
18. /**
19. * 读取文本。默认使用UTF-8编码
20. *
21. * @param page
22. * 页面的URL,比如 http://www.java2000.net
23. * @return 读取到的文本字符串
24. */
25. public static
26. return getPage(page, "UTF-8");
27. }
28. /**
29. * 读取文本
30. *
31. * @param page
32. * 页面的URL,比如 http://www.java2000.net
33. * @param charset
34. * 页面的编码
35. * @return 读取到的文本字符串
36. */
37. public static
38. null;
39. int count = 3;
40. do
41. str = _getPage(page, charset);
42. if (str == null || str.length() == 0) {
43. try
44. 1000);
45. catch
46. e.printStackTrace();
47. }
48. }
49. while (str == null && count-- > 0);
50. return
51. }
52. private static
53. try
54. new
55. HttpURLConnection con = (HttpURLConnection) url.openConnection();
56. // 增加了浏览器的类型,就用Firefox好了,也许
57. con
58. .setRequestProperty(
59. "User-Agent",
60. "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727)");
61. int index = page.indexOf("/", 10);
62. "Host", index == -1 ? page.substring(7) : page
63. 7, index));
64. InputStream is = con.getInputStream();
65. if (con.getContentEncoding() != null
66. "gzip")) {
67. new
68. }
69. new BufferedReader(new
70. charset));
71. new
72. String line;
73. while ((line = reader.readLine()) != null) {
74. b.append(line);
75. b.append(BR);
76. }
77. reader.close();
78. return
79. catch
80. "NOT FOUND:"
81. return null;
82. catch
83. "Timeout:"
84. return null;
85. catch
86. ex.printStackTrace();
87. return null;
88. }
89. }
90. public static String postPage(String page, String msg) throws
91. new
92. HttpURLConnection con = (HttpURLConnection) url.openConnection();
93. true); // POST方式
94. con
95. .setRequestProperty(
96. "User-Agent",
97. "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727)");
98. int index = page.indexOf("/", 10);
99. "Host", index == -1 ? page.substring(7) : page
100. 7, index));
101. "POST");
102. "Content-Type", "application/x-www-form-urlencoded");
103. // 输出流,写数据
104. "UTF-8"));
105. InputStream is = con.getInputStream();
106. if (con.getContentEncoding() != null
107. "gzip")) {
108. new
109. }
110. new BufferedReader(new
111. "UTF-8")); // 读取结果
112. new
113. String line;
114. while ((line = reader.readLine()) != null) {
115. b.append(line);
116. b.append(BR);
117. }
118. os.close();
119. reader.close();
120. return
121. }
122. }
package com.laozizhu.tools;import java.io.BufferedReader;import java.io.FileNotFoundException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.net.ConnectException;import java.net.HttpURLConnection;import java.net.URL;import java.util.zip.GZIPInputStream;/** * 读取URL的文本工具 * * @author 赵学庆 www.java2000.net */public class PageService { private static final String BR = "/r/n"; /** * 读取文本。默认使用UTF-8编码 * * @param page * 页面的URL,比如 http://www.java2000.net * @return 读取到的文本字符串 */ public static String getPage(String page) { return getPage(page, "UTF-8"); } /** * 读取文本 * * @param page * 页面的URL,比如 http://www.java2000.net * @param charset * 页面的编码 * @return 读取到的文本字符串 */ public static String getPage(String page, String charset) { String str = null; int count = 3; do { str = _getPage(page, charset); if (str == null || str.length() == 0) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } while (str == null && count-- > 0); return str; } private static String _getPage(String page, String charset) { try { URL url = new URL(page); HttpURLConnection con = (HttpURLConnection) url.openConnection(); // 增加了浏览器的类型,就用Firefox好了,也许 con .setRequestProperty( "User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"); int index = page.indexOf("/", 10); con.setRequestProperty("Host", index == -1 ? page.substring(7) : page .substring(7, index)); InputStream is = con.getInputStream(); if (con.getContentEncoding() != null && con.getContentEncoding().equalsIgnoreCase("gzip")) { is = new GZIPInputStream(con.getInputStream()); } BufferedReader reader = new BufferedReader(new InputStreamReader(is, charset)); StringBuilder b = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { b.append(line); b.append(BR); } reader.close(); return b.toString(); } catch (FileNotFoundException ex) { System.out.println("NOT FOUND:" + page); return null; } catch (ConnectException ex) { System.out.println("Timeout:" + page); return null; } catch (Exception ex) { ex.printStackTrace(); return null; } } public static String postPage(String page, String msg) throws Exception { URL url = new URL(page); HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setDoOutput(true); // POST方式 con .setRequestProperty( "User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"); int index = page.indexOf("/", 10); con.setRequestProperty("Host", index == -1 ? page.substring(7) : page .substring(7, index)); con.setRequestMethod("POST"); con.addRequestProperty("Content-Type", "application/x-www-form-urlencoded"); OutputStream os = con.getOutputStream(); // 输出流,写数据 os.write(msg.getBytes("UTF-8")); InputStream is = con.getInputStream(); if (con.getContentEncoding() != null && con.getContentEncoding().equalsIgnoreCase("gzip")) { is = new GZIPInputStream(con.getInputStream()); } BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); // 读取结果 StringBuilder b = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { b.append(line); b.append(BR); } os.close(); reader.close(); return b.toString(); }}
给我老师的人工智能教程打call!
你好! 这是你第一次使用 **Markdown编辑器** 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。
新的改变
我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:
- 全新的界面设计 ,将会带来全新的写作体验;
- 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
- 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
- 全新的 KaTeX数学公式 语法;
- 增加了支持甘特图的mermaid语法1
- 增加了 多屏幕编辑 Markdown文章功能;
- 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
- 增加了 检查列表 功能。
功能快捷键
撤销:Ctrl/Command + Z 重做:Ctrl/Command + Y 加粗:Ctrl/Command + B 斜体:Ctrl/Command + I 标题:Ctrl/Command + Shift + H 无序列表:Ctrl/Command + Shift + U 有序列表:Ctrl/Command + Shift + O 检查列表:Ctrl/Command + Shift + C 插入代码:Ctrl/Command + Shift + K 插入链接:Ctrl/Command + Shift + L 插入图片:Ctrl/Command + Shift + G
合理的创建标题,有助于目录的生成
直接输入1次#,并按下space后,将生成1级标题。 输入2次#,并按下space后,将生成2级标题。 以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。
如何改变文本的样式
强调文本 强调文本
加粗文本 加粗文本
标记文本
删除文本
引用文本
H2O is是液体。
210 运算结果是 1024.
插入链接与图片
链接: link.
图片:
带尺寸的图片:
当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。
如何插入一段漂亮的代码片
去博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.
// An highlighted block var foo = 'bar';
生成一个适合你的列表
- 项目
- 项目
- 项目
- 项目1
- 项目2
- 项目3
创建一个表格
一个简单的表格是这么创建的:
项目 | Value |
电脑 | $1600 |
手机 | $12 |
导管 | $1 |
设定内容居中、居左、居右
使用:---------:居中 使用:----------居左 使用----------:居右
第一列 | 第二列 | 第三列 |
第一列文本居中 | 第二列文本居右 | 第三列文本居左 |
SmartyPants
SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:
TYPE | ASCII | HTML |
Single backticks |
| ‘Isn’t this fun?’ |
Quotes |
| “Isn’t this fun?” |
Dashes |
| – is en-dash, — is em-dash |
创建一个自定义列表
HTML
Authors John Luke
如何创建一个注脚
一个具有注脚的文本。2
注释也是必不可少的
Markdown将文本转换为 HTML。
KaTeX数学公式
您可以使用渲染LaTeX数学表达式 KaTeX:
Gamma公式展示
你可以找到更多关于的信息 LaTeX 数学表达式here.
新的甘特图功能,丰富你的文章
gantt
dateFormat YYYY-MM-DD
title Adding GANTT diagram functionality to mermaid
section 现有任务
已完成 :done, des1, 2014-01-06,2014-01-08
进行中 :active, des2, 2014-01-09, 3d
计划一 : des3, after des2, 5d
计划二 : des4, after des3, 5d
- 关于 甘特图 语法,参考 这儿,
UML 图表
可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图::
张三 李四 王五 你好!李四, 最近怎么样? 你最近怎么样,王五? 我很好,谢谢! 我很好,谢谢! 李四想了很长时间, 文字太长了 不适合放在一行. 打量着王五... 很好... 王五, 你怎么样? 张三 李四 王五
这将产生一个流程图。:
链接
长方形
圆
圆角长方形
菱形
- 关于 Mermaid 语法,参考 这儿,
FLowchart流程图
我们依旧会支持flowchart的流程图:
- 关于 Flowchart流程图 语法,参考 这儿.
导出与导入
导出
如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。
导入
如果你想加载一篇你写过的.md文件或者.html文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入, 继续你的创作。
- mermaid语法说明 ↩︎
- 注脚的解释 ↩︎