最近在学习搜索方面的东西,需要了解网络爬虫方面的知识,虽然有很多开源的强大的爬虫,但本着学习的态度,自己写了一个简单的网络爬虫,以便了解其中原理。
首先介绍每个类的功能:
DownloadPage.java的功能是下载此超链接的页面源代码.
FunctionUtils.java 的功能是提供不同的静态方法,包括:页面链接正则表达式匹配,获取URL链接的元素,判断是否创建文件,获取页面的Url并将其转换为规范的Url,截取网页网页源文件的目标内容。
HrefOfPage.java 的功能是获取页面源代码的超链接。
UrlDataHanding.java 的功能是整合各个给类,实现url到获取数据到数据处理类。
UrlQueue.java 的未访问Url队列。
VisitedUrlQueue.java 已访问过的URL队列。
下面介绍一下每个类的源代码:
DownloadPage.java 此类要用到HttpClient组件。
1.View Code
2. package com.sreach.spider;
3.
4. import java.io.IOException;
5. import org.apache.http.HttpEntity;
6. import org.apache.http.HttpResponse;
7. import org.apache.http.client.ClientProtocolException;
8. import org.apache.http.client.HttpClient;
9. import org.apache.http.client.methods.HttpGet;
10. import org.apache.http.impl.client.DefaultHttpClient;
11. import org.apache.http.util.EntityUtils;
12.
13. public class DownloadPage
14. {
15.
16. /**
17. * 根据URL抓取网页内容
18. *
19. * @param url
20. * @return
21. */
22. public static String getContentFormUrl(String url)
23. {
24. /* 实例化一个HttpClient客户端 */
25. HttpClient client = new DefaultHttpClient();
26. HttpGet getHttp = new HttpGet(url);
27.
28. String content = null;
29.
30. HttpResponse response;
31. try
32. {
33. /*获得信息载体*/
34. response = client.execute(getHttp);
35. HttpEntity entity = response.getEntity();
36.
37. VisitedUrlQueue.addElem(url);
38.
39. if (entity != null)
40. {
41. /* 转化为文本信息 */
42. content = EntityUtils.toString(entity);
43.
44. /* 判断是否符合下载网页源代码到本地的条件 */
45. if (FunctionUtils.isCreateFile(url)
46. && FunctionUtils.isHasGoalContent(content) != -1)
47. {
48. FunctionUtils.createFile(FunctionUtils
49. .getGoalContent(content), url);
50. }
51. }
52.
53. } catch (ClientProtocolException e)
54. {
55. e.printStackTrace();
56. } catch (IOException e)
57. {
58. e.printStackTrace();
59. } finally
60. {
61. client.getConnectionManager().shutdown();
62. }
63.
64. return content;
65. }
66.
67. }
FunctionUtils.java 此类的方法均为static方法
1.View Code
2.
3.package com.sreach.spider;
4.
5.import java.io.BufferedWriter;
6.import java.io.File;
7.import java.io.FileOutputStream;
8.import java.io.IOException;
9.import java.io.OutputStreamWriter;
10.import java.util.regex.Matcher;
11.import java.util.regex.Pattern;
12.
13.public class FunctionUtils
14.{
15.
16. /**
17. * 匹配超链接的正则表达式
18. */
19. private static String pat = "http://www\\.oschina\\.net/code/explore/.*/\\w+\\.[a-zA-Z]+";
20. private static Pattern pattern = Pattern.compile(pat);
21.
22. private static BufferedWriter writer = null;
23.
24. /**
25. * 爬虫搜索深度
26. */
27. public static int depth = 0;
28.
29. /**
30. * 以"/"来分割URL,获得超链接的元素
31. *
32. * @param url
33. * @return
34. */
35. public static String[] divUrl(String url)
36. {
37. return url.split("/");
38. }
39.
40. /**
41. * 判断是否创建文件
42. *
43. * @param url
44. * @return
45. */
46. public static boolean isCreateFile(String url)
47. {
48. Matcher matcher = pattern.matcher(url);
49.
50. return matcher.matches();
51. }
52.
53. /**
54. * 创建对应文件
55. *
56. * @param content
57. * @param urlPath
58. */
59. public static void createFile(String content, String urlPath)
60. {
61. /* 分割url */
62. String[] elems = divUrl(urlPath);
63. StringBuffer path = new StringBuffer();
64.
65. File file = null;
66. for (int i = 1; i < elems.length; i++)
67. {
68. if (i != elems.length - 1)
69. {
70.
71. path.append(elems[i]);
72. path.append(File.separator);
73. file = new File("D:" + File.separator + path.toString());
74.
75. }
76.
77. if (i == elems.length - 1)
78. {
79. Pattern pattern = Pattern.compile("\\w+\\.[a-zA-Z]+");
80. Matcher matcher = pattern.matcher(elems[i]);
81. if ((matcher.matches()))
82. {
83. if (!file.exists())
84. {
85. file.mkdirs();
86. }
87. String[] fileName = elems[i].split("\\.");
88. file = new File("D:" + File.separator + path.toString()
89. + File.separator + fileName[0] + ".txt");
90. try
91. {
92. file.createNewFile();
93. writer = new BufferedWriter(new OutputStreamWriter(
94. new FileOutputStream(file)));
95. writer.write(content);
96. writer.flush();
97. writer.close();
98. System.out.println("创建文件成功");
99. } catch (IOException e)
100. {
101. e.printStackTrace();
102. }
103.
104. }
105. }
106.
107. }
108. }
109.
110. /**
111. * 获取页面的超链接并将其转换为正式的A标签
112. *
113. * @param href
114. * @return
115. */
116. public static String getHrefOfInOut(String href)
117. {
118. /* 内外部链接最终转化为完整的链接格式 */
119. String resultHref = null;
120.
121. /* 判断是否为外部链接 */
122. if (href.startsWith("http://"))
123. {
124. resultHref = href;
125. } else
126. {
127. /* 如果是内部链接,则补充完整的链接地址,其他的格式忽略不处理,如:a href="#" */
128. if (href.startsWith("/"))
129. {
130. resultHref = "http://www.oschina.net" + href;
131. }
132. }
133.
134. return resultHref;
135. }
136.
137. /**
138. * 截取网页网页源文件的目标内容
139. *
140. * @param content
141. * @return
142. */
143. public static String getGoalContent(String content)
144. {
145. int sign = content.indexOf("
146. String signContent = content.substring(sign);
147.
148. int start = signContent.indexOf(">");
149. int end = signContent.indexOf("
");150.
151. return signContent.substring(start + 1, end);
152. }
153.
154. /**
155. * 检查网页源文件中是否有目标文件
156. *
157. * @param content
158. * @return
159. */
160. public static int isHasGoalContent(String content)
161. {
162. return content.indexOf("
163. }
164.
165.}
HrefOfPage.java 此类为获取页面的超链接
1.View Code
2.
3.package com.sreach.spider;
4.
5.public class HrefOfPage
6.{
7. /**
8. * 获得页面源代码中超链接
9. */
10. public static void getHrefOfContent(String content)
11. {
12. System.out.println("开始");
13. String[] contents = content.split("
14. for (int i = 1; i < contents.length; i++)
16. int endHref = contents[i].indexOf("\"");
18. String aHref = FunctionUtils.getHrefOfInOut(contents[i].substring(
23. String href = FunctionUtils.getHrefOfInOut(aHref);
25. if (!UrlQueue.isContains(href)
26. && href.indexOf("/code/explore") != -1
27. && !VisitedUrlQueue.isContains(href))
34. System.out.println(UrlQueue.size() + "--抓取到的连接数");
35. System.out.println(VisitedUrlQueue.size() + "--已处理的页面数");
UrlDataHanding.java 此类主要是从未访问队列中获取url,下载页面,分析url,保存已访问url等操作,实现Runnable接口
5.public class UrlDataHanding implements Runnable
8. * 下载对应页面并分析出页面对应的URL放在未访问队列中。
11. public void dataHanding(String url)
13. HrefOfPage.getHrefOfContent(DownloadPage.getContentFormUrl(url));
18. while(!UrlQueue.isEmpty())
20. dataHanding(UrlQueue.outElem());
UrlQueue.java 此类主要是用来存放未访问的URL队列
5.import java.util.LinkedList;
10. public static LinkedList urlQueue = new LinkedList();
13. public static final int MAX_SIZE = 10000;
15. public synchronized static void addElem(String url)
20. public synchronized static String outElem()
22. return urlQueue.removeFirst();
25. public synchronized static boolean isEmpty()
27. return urlQueue.isEmpty();
35. public static boolean isContains(String url)
37. return urlQueue.contains(url);
VisitedUrlQueue.java 主要是保存已访问过的URL,使用HashSet来保存,主要是考虑到每个访问过的URL是不同。HashSet刚好符合这个要求
12.public class VisitedUrlQueue
14. public static HashSet visitedUrlQueue = new HashSet();
16. public synchronized static void addElem(String url)
21. public synchronized static boolean isContains(String url)
23. return visitedUrlQueue.contains(url);
26. public synchronized static int size()
28. return visitedUrlQueue.size();
3.import java.sql.SQLException;
5.import com.sreach.spider.UrlDataHanding;
6.import com.sreach.spider.UrlQueue;
10. public static void main(String[] args) throws SQLException
12. String url = "http://www.oschina.net/code/explore/achartengine/client/AndroidManifest.xml";
13. String url1 = "http://www.oschina.net/code/explore";
14. String url2 = "http://www.oschina.net/code/explore/achartengine";
15. String url3 = "http://www.oschina.net/code/explore/achartengine/client";
23. UrlDataHanding[] url_Handings = new UrlDataHanding[10];
25. for(int i = 0 ; i < 10 ; i++)
27. url_Handings[i] = new UrlDataHanding();
28. new Thread(url_Handings[i]).start();
说明一下:由于抓取的是针对oschina的,所以里面的url正则表达式不适合其他网站,需要自己修改一下。你也可以写成xml来配置。