基础库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

taobao_loader.dart 7.2 KiB

пре 4 година
пре 4 година
пре 4 година
пре 4 година
пре 4 година
пре 4 година
пре 4 година
пре 4 година
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. import 'dart:convert';
  2. import 'dart:io';
  3. import 'package:dio/dio.dart';
  4. import 'package:dio_cookie_manager/dio_cookie_manager.dart';
  5. import 'package:zhiying_comm/util/taobao/goods_pic_model.dart';
  6. import 'package:zhiying_comm/zhiying_comm.dart';
  7. import 'package:cookie_jar/cookie_jar.dart';
  8. import 'package:convert/convert.dart';
  9. import 'package:crypto/crypto.dart';
  10. // 淘宝详情图抓取
  11. class TaobaoLoader {
  12. static Future<List<String>> loadImages(String id) async {
  13. return _loadImagesNew(id);
  14. }
  15. static Future<List<String>> _loadImages1(String id) async {
  16. String url =
  17. 'http://h5api.m.taobao.com/h5/mtop.taobao.detail.getdesc/6.0/?api=mtop.taobao.detail.getdesc&appkey=12574478&data={"type":"0","f":"TB1AsvbfnqWBKNjSZFx8qwpLpla","id":"${id.toString()}"}&dataType=json&jsv=2.4.11&sign=e93a97b7e9a9a459297f4e689051c895&t=1538180732308&type=json';
  18. Dio dio = Dio();
  19. Response response = await dio.get(url);
  20. // Logger.debug(response.data.toString());
  21. Map<String, dynamic> json = Map<String, dynamic>.from(response.data);
  22. List<String> images = List();
  23. try {
  24. Map<String, dynamic> data = json['data'];
  25. List list = json['data']['wdescContent']['pages'];
  26. for (var item in list) {
  27. Logger.debug(item);
  28. RegExp exp = new RegExp("(?<=<img(.*?)>)(.*?)(?=</img>)");
  29. String image = exp.stringMatch(item.toString());
  30. if (image != null && image != '') {
  31. if (image.startsWith('//')) {
  32. images.add('http:' + image);
  33. } else if (image.startsWith('https://') || image.startsWith('http://')) {
  34. images.add(image);
  35. }
  36. }
  37. }
  38. } catch (err) {
  39. Logger.error(err);
  40. }
  41. return images;
  42. }
  43. ///方法说明:通过破解淘宝签名接口获取商品详情图片
  44. ///流程:第一次请求接口拿到cookie数据,拼接签名数据,第二次请求接口拿到图片连接数据
  45. ///方法地址
  46. ///https://darktiantian.github.io/%E8%AE%B0%E4%B8%80%E6%AC%A1%E6%B7%98%E5%AE%9D%E6%8E%A5%E5%8F%A3sign%E7%AD%BE%E5%90%8D%E7%A0%B4%E8%A7%A3/
  47. static Future<List<String>> _loadImagesNew(String id) async {
  48. String data = "{\"item_num_id\":\"" + id + "\"}";
  49. String time = DateTime.now().millisecondsSinceEpoch.toString();
  50. String appkey = "12574478"; //文章中使用的appkey
  51. String url = "https://h5api.m.taobao.com/h5/mtop.wdetail.getitemdescx/4.9/?jsv=2.4.11&appKey=$appkey&t=$time"
  52. "&sign=FAKE_SIGN_WITH_ANYTHING&api=mtop.wdetail.getItemDescx&v=4.9&type=jsonp&dataType=jsonp&callback=mtopjsonp2&data="
  53. "$data";
  54. Logger.log("url: " + url);
  55. Dio dio = Dio(BaseOptions(responseType: ResponseType.plain));
  56. var cookieJar = CookieJar();
  57. //dio绑定cookie管理器,以便第一次请求后获取cookie数据
  58. dio.interceptors.add(CookieManager(cookieJar));
  59. Map<String, dynamic> headers = new Map();
  60. headers['User-Agent'] =
  61. "Mozilla/5.0 (iPhone; CPU iPhone OS 9_3_4 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13G35 Safari/601.1";
  62. Options options = new Options(headers: headers);
  63. //首次请求获取cookie
  64. await dio.get(url, options: options);
  65. String token = "";
  66. String _m_h5_tk = "";
  67. String enc_token = "";
  68. //根据第一次请求后返回的cookie拿到需要的数据
  69. List<Cookie> cookieList = cookieJar.loadForRequest(Uri.parse(url));
  70. for (int i = 0; i < cookieList.length; i++) {
  71. Cookie cookie = cookieList[i];
  72. Logger.log(cookie.name + " : " + cookie.value);
  73. if ("_m_h5_tk" == cookie.name) {
  74. _m_h5_tk = cookie.value;
  75. List<String> token_with_time = cookie.value.split("_");
  76. if (token_with_time.length > 0) {
  77. token = token_with_time[0];
  78. }
  79. }
  80. if ("_m_h5_tk_enc" == cookie.name) {
  81. enc_token = cookie.value;
  82. }
  83. }
  84. //设置第二次请求的cookie数据
  85. Map<String, dynamic> headers2 = new Map();
  86. headers2['cookie'] = "_m_h5_tk=$_m_h5_tk; _m_h5_tk_enc=$enc_token;"
  87. "User-Agent=Mozilla/5.0 (iPhone; CPU iPhone OS 9_3_4 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13G35 Safari/601.1";
  88. Options options2 = new Options(headers: headers2);
  89. //设置签名
  90. String time2 = DateTime.now().millisecondsSinceEpoch.toString();
  91. String sign = token + "&" + time2 + "&" + appkey + "&" + data;
  92. String mySign = string2Md5(sign);
  93. //设置第二次请求的url
  94. String url2 = "https://h5api.m.taobao.com/h5/mtop.wdetail.getitemdescx/4.9/?jsv=2.4.11&appKey=$appkey&t=$time2"
  95. "&sign=$mySign&api=mtop.wdetail.getItemDescx&v=4.9&type=jsonp&dataType=jsonp&callback=mtopjsonp2&data="
  96. "$data";
  97. //进行第二次网络请求拿到图片数据
  98. Dio dio2 = Dio(BaseOptions(responseType: ResponseType.plain));
  99. Response response2 = await dio2.get(url2, options: options2);
  100. Logger.log(response2.data);
  101. //根据返回的数据,拼接图片链接数据
  102. String result2 = response2.data;
  103. String object = result2.substring(result2.indexOf("(") + 1, result2.length - 1);
  104. Logger.log(object);
  105. var json = jsonDecode(object);
  106. GoodsPicModel model = GoodsPicModel.fromJson(json);
  107. List<String> images = List();
  108. if (null != model.data.images && model.data.images.length > 0) {
  109. /**
  110. * images字段的数据,在前面拼接好https:就可以作为商品详情的图片链接使用了
  111. */
  112. List<String> Images = model.data.images;
  113. List<String> mPicList = [];
  114. for (String pic in Images) {
  115. if (pic.isNotEmpty) {
  116. if (pic.startsWith("http")) {
  117. mPicList.add(pic);
  118. } else {
  119. mPicList.add("https:" + pic);
  120. }
  121. }
  122. }
  123. Logger.log("mPicList图片:" + mPicList.length.toString() + "\n" + mPicList.toString());
  124. if (mPicList.length > 0) {
  125. return mPicList;
  126. }
  127. } else {
  128. if (null != model.data.pages && model.data.pages.length > 0) {
  129. /**
  130. * pages字段的数据,数组中可能有多张图片的链接数据,以<img></img>标签框起来的
  131. * 先去掉前面的<img>标签,再以</img>标签分割各个图片链接数据,
  132. * 最后每个数据拼接上https:就可以作为商品详情图片链接返回了
  133. * 经测试images字段和pages字段的数据是相同的,所以取一个字段的数据返回就可以了
  134. */
  135. List<String> pages = model.data.pages;
  136. List<String> mPicList = [];
  137. for (String pic in pages) {
  138. String pic1 = pic.replaceAll("<img>", "");
  139. List<String> pic2 = pic1.split("</img>");
  140. if (pic2.length > 0) {
  141. for (String s in pic2) {
  142. if (s.isNotEmpty) {
  143. if (s.startsWith("http")) {
  144. mPicList.add(s);
  145. } else {
  146. mPicList.add("https:" + s);
  147. }
  148. }
  149. }
  150. }
  151. }
  152. Logger.log("图片2:" + mPicList.length.toString() + "\n" + mPicList.toString());
  153. if (mPicList.length > 0) {
  154. return mPicList;
  155. }
  156. }
  157. }
  158. return images;
  159. }
  160. // md5 加密
  161. static String string2Md5(String data) {
  162. var content = new Utf8Encoder().convert(data);
  163. var digest = md5.convert(content);
  164. return hex.encode(digest.bytes);
  165. }
  166. }