Android进阶(十三)网络爬虫&json应用

举报
SHQ5785 发表于 2020/12/30 01:13:05 2020/12/30
【摘要】     刚开始接触网络爬虫,怎一个“菜”字了得!经过几次的折磨,对其原理以及其中用到的json技术有了大致的了解,故作一总结,供有同样迷惑的朋友参考学习。     自己爬取的网站内容为12306的余票查询模块。利用火狐浏览器为Web开发者置的Web控制台,可得到爬取网页的请求网址,如下图所示: 其中的请求网址即为我们需要爬取的网址。另外,可得知其请求协议采用的是Htt...

    刚开始接触网络爬虫,怎一个“菜”字了得!经过几次的折磨,对其原理以及其中用到的json技术有了大致的了解,故作一总结,供有同样迷惑的朋友参考学习。

    自己爬取的网站内容为12306的余票查询模块。利用火狐浏览器为Web开发者置的Web控制台,可得到爬取网页的请求网址,如下图所示:

其中的请求网址即为我们需要爬取的网址。另外,可得知其请求协议采用的是Https协议,采用GET方式访问。爬取源代码如下所示:
 

  
  1. public static String queryDate = "2015-04-19";
  2. public static String from_station = "JNK";
  3. public static String to_station = "BJP";
  4. public static void main(String[] args) throws Exception {
  5. HostnameVerifier hv = new HostnameVerifier() {
  6. public boolean verify(String urlHostName, SSLSession session) {
  7. System.out.println("Warning: URL Host: " + urlHostName
  8. + " vs. " + session.getPeerHost());
  9. return true;
  10. }
  11. };
  12. String url = "https://kyfw.12306.cn/otn/lcxxcx/query?purpose_codes=ADULT&queryDate="
  13. + queryDate
  14. + "&from_station="
  15. + from_station
  16. + "&to_station="
  17. + to_station;
  18. ProtocolUrlValidator.trustAllHttpsCertificates();
  19. HttpsURLConnection.setDefaultHostnameVerifier(hv);
  20. String result = WebServiceUtil.invokeByHTTPGET(url, null);
  21. Gson gson = new Gson();
  22. Trains trains = gson.fromJson(result, Trains.class);
  23. List<Item> items = trains.getData().getItems();
  24. if (trains.getHttpstatus() != 200) {
  25. trains.getMessages();
  26. } else {
  27. if (items != null && items.size() != 0)
  28. for (Item item : items) {
  29. System.out.println(item);
  30. }
  31. }
  32. }
  33. }
<span style="font-size:14px;">由于使用的协议为Https,故访问之前需要先进行证书的校验。其中蓝色代码块为我们需要访问的网址,涉及到的invokeByHTTPGET(url,null)代码如下所示:</span>
 

  
  1. <span style="font-size:18px;">public class WebServiceUtil {
  2. /**
  3. * 通过SOAP1.1协议调用Web服务
  4. *
  5. * @param wsdl WSDL路径
  6. * @param method 方法名
  7. * @param namespace 命名空间
  8. * @param headerParameters 头参数
  9. * @param bodyParameters 体参数
  10. * @param isBodyParametersNS 体参数是否有命名空间
  11. * @return String
  12. * @throws Exception
  13. */
  14. public static String invokeBySoap11(String wsdl, String method,
  15. String namespace, Map<String, String> headerParameters,
  16. Map<String, String> bodyParameters, boolean isBodyParametersNS)
  17. throws Exception {
  18. StringBuffer soapOfResult = null;
  19. // 去除 ?wsdl,获取方法列表
  20. int length = wsdl.length();
  21. wsdl = wsdl.substring(0, length - 5);
  22. URL url = new URL(wsdl);
  23. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  24. conn.setRequestMethod("POST");
  25. conn.setDoInput(true);
  26. conn.setDoOutput(true);
  27. conn.setRequestProperty("Content-Type", "text/xml;charset=utf-8");
  28. OutputStream out = conn.getOutputStream();
  29. // 获取soap1.1版本消息
  30. StringBuilder sb = new StringBuilder();
  31. sb.append("<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
  32. xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" ");
  33. sb.append("xmlns:ns0=\"" + namespace + "\"");
  34. sb.append(">");
  35. if (headerParameters != null) {
  36. sb.append("<soap:Header>");
  37. for (Entry<String, String> headerParameter : headerParameters
  38. .entrySet()) {
  39. sb.append("<ns0:");
  40. sb.append(headerParameter.getKey());
  41. sb.append(">");
  42. sb.append(headerParameter.getValue());
  43. sb.append("</ns0:");
  44. sb.append(headerParameter.getKey());
  45. sb.append(">");
  46. }
  47. sb.append("</soap:Header>");
  48. }
  49. sb.append("<soap:Body><ns0:");
  50. sb.append(method);
  51. sb.append(">");
  52. // 输入参数
  53. if (bodyParameters != null) {
  54. for (Entry<String, String> inputParameter : bodyParameters
  55. .entrySet()) {
  56. if (isBodyParametersNS) {
  57. sb.append("<ns0:");
  58. sb.append(inputParameter.getKey());
  59. sb.append(">");
  60. sb.append(inputParameter.getValue());
  61. sb.append("</ns0:");
  62. sb.append(inputParameter.getKey());
  63. sb.append(">");
  64. } else {
  65. sb.append("<");
  66. sb.append(inputParameter.getKey());
  67. sb.append(">");
  68. sb.append(inputParameter.getValue());
  69. sb.append("</");
  70. sb.append(inputParameter.getKey());
  71. sb.append(">");
  72. }
  73. }
  74. }
  75. sb.append("</ns0:");
  76. sb.append(method);
  77. sb.append("></soap:Body></soap:Envelope>");
  78. //System.out.println(sb.toString());
  79. out.write(sb.toString().getBytes());
  80. int code = conn.getResponseCode();
  81. if (code == 200) {
  82. InputStream is = conn.getInputStream();
  83. byte[] b = new byte[1024];
  84. int len = 0;
  85. soapOfResult = new StringBuffer();
  86. while ((len = is.read(b)) != -1) {
  87. String s = new String(b, 0, len, "UTF-8");
  88. soapOfResult.append(s);
  89. }
  90. }
  91. conn.disconnect();
  92. return soapOfResult == null ? null : soapOfResult.toString();
  93. }
  94. /**
  95. * 通过SOAP1.2协议调用Web服务
  96. *
  97. * @param wsdl
  98. * @param method
  99. * @param namespace
  100. * @param headerParameters
  101. * @param bodyParameters
  102. * @param isBodyParametersNS
  103. * @return
  104. * @throws Exception
  105. */
  106. public static String invokeBySoap12(String wsdl, String method,
  107. String namespace, Map<String, String> headerParameters,
  108. Map<String, String> bodyParameters, boolean isBodyParametersNS)
  109. throws Exception {
  110. StringBuffer soapOfResult = null;
  111. // 去除 ?wsdl
  112. int length = wsdl.length();
  113. wsdl = wsdl.substring(0, length - 5);
  114. URL url = new URL(wsdl);
  115. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  116. conn.setRequestMethod("POST");
  117. conn.setDoInput(true);
  118. conn.setDoOutput(true);
  119. conn.setRequestProperty("Content-Type", "text/xml;charset=utf-8");
  120. OutputStream out = conn.getOutputStream();
  121. // 获取soap1.1版本消息
  122. StringBuilder sb = new StringBuilder();
  123. sb.append("<soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
  124. xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ");
  125. sb.append("xmlns:ns0=\"" + namespace + "\"");
  126. sb.append(">");
  127. if (headerParameters != null) {
  128. sb.append("<soap12:Header>");
  129. for (Entry<String, String> headerParameter : headerParameters
  130. .entrySet()) {
  131. sb.append("<ns0:");
  132. sb.append(headerParameter.getKey());
  133. sb.append(">");
  134. sb.append(headerParameter.getValue());
  135. sb.append("</ns0:");
  136. sb.append(headerParameter.getKey());
  137. sb.append(">");
  138. }
  139. sb.append("</soap12:Header>");
  140. }
  141. sb.append("<soap12:Body><ns0:");
  142. sb.append(method);
  143. sb.append(">");
  144. // 输入参数
  145. if (bodyParameters != null) {
  146. for (Entry<String, String> inputParameter : bodyParameters
  147. .entrySet()) {
  148. if (isBodyParametersNS) {
  149. sb.append("<ns0:");
  150. sb.append(inputParameter.getKey());
  151. sb.append(">");
  152. sb.append(inputParameter.getValue());
  153. sb.append("</ns0:");
  154. sb.append(inputParameter.getKey());
  155. sb.append(">");
  156. } else {
  157. sb.append("<");
  158. sb.append(inputParameter.getKey());
  159. sb.append(">");
  160. sb.append(inputParameter.getValue());
  161. sb.append("</");
  162. sb.append(inputParameter.getKey());
  163. sb.append(">");
  164. }
  165. }
  166. }
  167. sb.append("</ns0:");
  168. sb.append(method);
  169. sb.append("></soap12:Body></soap12:Envelope>");
  170. System.out.println(sb.toString());
  171. out.write(sb.toString().getBytes());
  172. int code = conn.getResponseCode();
  173. if (code == 200) {
  174. InputStream is = conn.getInputStream();
  175. byte[] b = new byte[1024];
  176. int len = 0;
  177. soapOfResult = new StringBuffer();
  178. while ((len = is.read(b)) != -1) {
  179. String s = new String(b, 0, len, "UTF-8");
  180. soapOfResult.append(s);
  181. }
  182. }
  183. conn.disconnect();
  184. return soapOfResult == null ? null : soapOfResult.toString();
  185. }
  186. /**
  187. * 通过HTTP POST传参方式调用服务
  188. *
  189. * @param urlPath
  190. * @param method
  191. * @param namespace
  192. * @param inputParameters
  193. * @return
  194. * @throws Exception
  195. */
  196. public static String invokeByHTTPPOST(String urlPath, Map<String, String> inputParameters)
  197. throws Exception {
  198. StringBuffer resultStr = null;
  199. URL url = new URL(urlPath);
  200. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  201. conn.setRequestMethod("POST");
  202. conn.setDoInput(true);
  203. conn.setDoOutput(true);
  204. conn.setRequestProperty("Content-Type",
  205. "application/x-www-form-urlencoded");
  206. StringBuilder sb = new StringBuilder();
  207. // 输入参数
  208. if (inputParameters != null) {
  209. for (Entry<String, String> inputParameter : inputParameters
  210. .entrySet()) {
  211. sb.append(inputParameter.getKey());
  212. sb.append("=");
  213. sb.append(inputParameter.getValue());
  214. sb.append("&");
  215. }
  216. sb.deleteCharAt(sb.length() - 1);
  217. }
  218. System.out.println(sb.toString());
  219. OutputStream out = conn.getOutputStream();
  220. out.write(sb.toString().getBytes());
  221. int code = conn.getResponseCode();
  222. if (code == 200) {
  223. InputStream is = conn.getInputStream();
  224. byte[] b = new byte[1024];
  225. int len = 0;
  226. resultStr = new StringBuffer();
  227. while ((len = is.read(b)) != -1) {
  228. String s = new String(b, 0, len, "UTF-8");
  229. resultStr.append(s);
  230. }
  231. }
  232. conn.disconnect();
  233. return resultStr == null ? null : resultStr.toString();
  234. }
  235. /**
  236. * 通过HTTP GET传参方式调用服务
  237. *
  238. * @param urlPath url路径
  239. * @param method 方法名
  240. * @param namespace 命名空间
  241. * @param inputParameters 输入参数
  242. * @return String
  243. * @throws Exception
  244. */
  245. public static String invokeByHTTPGET(String urlPath, Map<String, String> inputParameters)
  246. throws Exception {
  247. StringBuilder sb = new StringBuilder();
  248. sb.append(urlPath);
  249. // GET参数
  250. if (inputParameters != null) {
  251. sb.append("?");
  252. //entrySet()方法 返回此映射中包含的映射关系的 set 视图集合
  253. //Map.Entry表示单个映射关系即一个key+value
  254. for (Entry<String, String> inputParameter : inputParameters
  255. .entrySet()) {
  256. sb.append(inputParameter.getKey());
  257. sb.append("=");
  258. sb.append(inputParameter.getValue());
  259. sb.append("&");
  260. }
  261. //作用:去除最后一个拼接的'&'字符
  262. sb.deleteCharAt(sb.length() - 1);
  263. }
  264. System.out.println(sb.toString());
  265. URL url = new URL(sb.toString());
  266. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  267. conn.setRequestMethod("GET");
  268. conn.setDoOutput(true);
  269. int code = conn.getResponseCode();
  270. StringBuffer resultString = null;
  271. if (code == 200) {
  272. InputStream is = conn.getInputStream();
  273. byte[] b = new byte[4096];
  274. int len = 0;
  275. resultString = new StringBuffer();
  276. while ((len = is.read(b)) != -1) {
  277. String s = new String(b, 0, len, "UTF-8");
  278. //System.out.println(len+">>>>"+s);
  279. resultString.append(s);
  280. }
  281. }
  282. conn.disconnect();
  283. return resultString == null ? null : resultString.toString();
  284. }</span>
 

以上代码块涉及到的发送请求方式有通过SOAP1.1协议调用Web服务、通过SOAP1.2协议调用Web服务、

通过HTTP POST传参方式调用服务和通过HTTP GET传参方式调用服务。其具体的请求方式在源代码中以注释方式以详细给出,故此处不再赘述。

在爬取过程中,我们还需要用到json在线校验工具,网址为:点击打开链接。主要利用此工具完成的操作为:验证json格式的正确性,根据json串生成相应的POJO类。如下图所示:

                                                                                                                                           json格式校验

                                                                                                                                                                                                      生成POJO类

<span style="font-size:18px;">至此,网络爬虫的过程基本结束。此次实验的返回结果如下图所示:</span>
 

注:自己对GSon解析json还存在一定的误区。对于json串中的Key,其实是与相应类中的变量名一一对应的,否则,在解析式将会是null!例如,

以上的json串中存在key为data,则在创建POJO时,不可随意更变变量名,若将private List<Item> datas;改写为private List<Item> items;则会使变List<Item> items = trains.getData().getItems();返回null。若自己需要更改变量名的话,可以采用注解的方式解决,例如@SerializedName("datas")private List<Item> items;

文章来源: shq5785.blog.csdn.net,作者:No Silver Bullet,版权归原作者所有,如需转载,请联系作者。

原文链接:shq5785.blog.csdn.net/article/details/45115615

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。