5 b0 R1 d: f% E# N; s$ b$ {五一我教粉丝完成了她的第一次JS逆向实战讲实话五一我还沉浸在其中,希望这是一场梦永远这样下去,因为一些小小的举动让她可能感受到了我的真诚吧!请我五一吃了一顿饭~~嗯?不信?) U, ^4 [) j' O, P% W- u4 k N
/ [6 `+ N$ H: |2 O n* W$ I(拍个Vlog都说我P图----膨胀了?)图片为证!!!!!!右边👉那哥们没错就是本屌丝!!
7 E# r% d0 Q/ u: v0 E. Q
; V* E1 A2 h3 f9 r$ k% I/ y! o$ x% V1 V6 D5 `- K/ C# f
( y U5 N& A/ u: N
五一假期的时候,有一个粉丝找到了我,大致找我干什么呢?其实刚开始我也是很迷。我除了会写个爬虫跟段子实在想不到自身还有何优点呀!难道是我那该死的温柔??果不其然,专业的事情还是找到了我这个不专业的人。事情的经过它是这样子的:
6 f2 g( f- w0 K5 ]- U3 I. z, B4 U1 V( B1 y; d, B
粉丝:大佬!想问问你企业名片的数据那个加密怎么破解啊,我发现接口返回的数据是经过加密处理过的,虽然我写了一个Selenium版本的,能采集数据吧,就是慢!而且看着也很low一样。感觉自己就不是一个合格的爬虫工程师,作为一入坑爬虫没多久的我来说JS逆向压根没有思路…
% ]; M6 n0 r z7 \2 Y6 k1 Z9 H$ B
都叫我大佬了,你就算不是妹子。今天这事我也得给你办喽!再不专业我现学现卖也要厚着脸皮上!
- d% D) m3 B. C8 {! R/ M, i! E& D1 L: S4 A8 ^, R8 l X3 G
( z* S/ [/ m& m% F
起初我还是帮在Github跟一些博客找了相关的参考资料给她想着能打开她的一些思路,但是我发现事情并不是这样的。一个对逆向基本思路没有相关经验跟思路的她可能并不知道如何找到切入点,先干嘛?再干嘛?甚至是在Chrome内基本的调试操作都不太清楚—- i" `/ r) O+ y( ~
! I$ l: c# `6 S
最重要的一点是:参考的资料只包含了对数据加密破解的思路跟讲解,而这个网站在登陆的情况下对IP不仅有反爬措施更会冻结你的账号。所以呢!我就做了一把雷锋,把整个网站的爬虫代码都撸了出来,请看大屏幕:( K& }& J& a1 M! R# {& z
1 P4 O/ k$ F0 l
- |: C0 T" Z8 [: d+ ~
4 A c/ V6 w% B, H
: q( s. Y0 [& ~7 k- Z
! T5 D6 K. L D7 {& g
) E# b; `' w; N3 t
" l. ]: i! ^. y1 ^2 L% B
' H2 h% i& L, z7 N/ ~, o) d [0 `) R
" Q1 `4 S& L" ?4 q& P; S
8 a7 ^1 J3 Q- x1 V( g5 Z3 A来!不说那些没用的。整点实际的给大家。对了!完整代码仅供学习参考使用,有需要可以联系作者获取$ m# k1 |7 W \. i
- t# @3 s( G- d2 @5 |0 D首先打开她给我发的链接企名片,在未登陆的情况下看到网站确实是有一些让爬虫上瘾的数据。嘿!你左手右手一个慢动作,跟着我的操作一起走呀!光看着也不抵用噻0 D) o+ A/ ^! K" g
/ W1 c+ d3 c& q/ r$ {刷新页面,开发者工具打开,可以发现网页是js动态生成的,并没有发现你咱们想要的HTML。象征性的点击一下查看响应数据
7 Z1 J) e+ `4 ^' X
% ?8 Z1 r6 U' g' M4 o 我不知道productListVip这个接口内的响应数据是不是就有网站我们需要的数据!但是可以看到有一个数encrypt_data是经过处理的,初步看这只是一个Base64的编码,真的这么简单吗?我想它在编码之前是经过加密算法处理过的。因为很多网站对数据加密或多或少都是这样的套路,所以为了验证这个被处理的东东到底是个啥,我们需要先去破解它 ~/ m6 l* r8 M& ]0 k8 l
& x" d9 v" Y4 {: j
这个过程是快乐的,当然!它建立在你成功或有收获的基础之上。不然用Selenium来做它难道不香吗?还要什么自行车?9 o5 c1 _) Q7 o$ X* Y
参数encrypt_data既然是经过处理的,但是终归是要给用户看的,所以在它呈现到网页过程中肯定是有在中间的某个地方对这个数据做了对应的解密操作,不然搞一顿Base64的编码数据给用户看?毕竟大家不是程序员呀!$ ^/ {, a) K$ n2 ?+ x% w) S
: X/ V8 r2 }# U! i/ J* Q' e: u* T之前说到过对于一些请求、响应…参数加密的这种场景,去反推的思路有很多种,可以通过搜索关键字、也可以通过hook、也可以断点。思路是这样的,具体因站而异哈
9 p# A2 d) s2 K
. y% t8 g2 q6 H( q! k既然是JS生成我们在开发者工具中点击Sources,因为现在加密参数的那个请求它就是XHR,所以在右侧XHR断点调试栏添加它,这个功能支持XHR请求断点调试!
. `' v- R5 ] x# W2 K# y$ {+ A; Z0 e, ?' W' ]
OK!做好上面的一切我们刷新网站页面。然后断点跟预期中的一样,停了下来。我们单步跟进可以很直观的看到每一个参数传递的细节,直到发现了跟接口响应数据极度相似的参数e.data
" j/ l3 F' w1 c
" x* o/ ?8 Y2 `' x继续跟进发现e.data参数的数据通过一个函数实现。可以在Console中将这个函数调用执行一下。没错!函数Obiect(u.a)(e.encrypt_data)返回的内容正是网站页面呈现的数据。到了这一步我们能确定接口就是数据加载的接口,Base64编码也正是经过加密之后的数据3 h. v" m; \% X3 |$ U; z
. O# e, F$ J) M9 I7 ~
既然现在我们已经找到了真实的数据,那就证明它在呈现的时候就已经解密了,我们进到这个函数体内去继续寻找,发现了解密函数
& c# n0 y( Q1 N5 q; l
: O' V5 f- m, V/ U1 dfunction o(t)是一个解密函数,可以看到它先调用s函数,s函数是什么?等下我们进去看看就知道了!一共有四个参数,a.a.decode(t)这个参数是数据。等下下面看了s函数就明白了。另外三个参数固定的,最后JSON.parse格式化json数据$ @ w0 g, v% x8 ?' c
" K8 ~" P$ @3 h& E3 l; ~这个就是s函数,你觉得它主要功能是干嘛的呢?我猜它是做数据解密的,你看看这一大串不是解密算法就让我写代码不掉头发!这东西你要想了解它解密算法的原理用Python实现解密的话可以好好分析一下6 w/ k5 ?6 ~0 C3 _( E7 ^; B0 m
function s(t, e, i, n, a, s) {
/ Q4 e8 R$ f# N+ g9 m var o, r, c, l, u, d, h, p, f, v, m, g, b, y, _ = new Array(16843776,0,65536,16843780,16842756,66564,4,65536,1024,16843776,16843780,1024,16778244,16842756,16777216,4,1028,16778240,16778240,66560,66560,16842752,16842752,16778244,65540,16777220,16777220,65540,0,1028,66564,16777216,65536,16843780,4,16842752,16843776,16777216,16777216,1024,16842756,65536,66560,16777220,1024,4,16778244,66564,16843780,65540,16842752,16778244,16777220,1028,66564,16843776,1028,16778240,16778240,0,65540,66560,0,16842756), C = new Array(-2146402272,-2147450880,32768,1081376,1048576,32,-2146435040,-2147450848,-2147483616,-2146402272,-2146402304,-2147483648,-2147450880,1048576,32,-2146435040,1081344,1048608,-2147450848,0,-2147483648,32768,1081376,-2146435072,1048608,-2147483616,0,1081344,32800,-2146402304,-2146435072,32800,0,1081376,-2146435040,1048576,-2147450848,-2146435072,-2146402304,32768,-2146435072,-2147450880,32,-2146402272,1081376,32,32768,-2147483648,32800,-2146402304,1048576,-2147483616,1048608,-2147450848,-2147483616,1048608,1081344,0,-2147450880,32800,-2147483648,-2146435040,-2146402272,1081344), w = new Array(520,134349312,0,134348808,134218240,0,131592,134218240,131080,134217736,134217736,131072,134349320,131080,134348800,520,134217728,8,134349312,512,131584,134348800,134348808,131592,134218248,131584,131072,134218248,8,134349320,512,134217728,134349312,134217728,131080,520,131072,134349312,134218240,0,512,131080,134349320,134218240,134217736,512,0,134348808,134218248,131072,134217728,134349320,8,131592,131584,134217736,134348800,134218248,520,134348800,131592,8,134348808,131584), x = new Array(8396801,8321,8321,128,8396928,8388737,8388609,8193,0,8396800,8396800,8396929,129,0,8388736,8388609,1,8192,8388608,8396801,128,8388608,8193,8320,8388737,1,8320,8388736,8192,8396928,8396929,129,8388736,8388609,8396800,8396929,129,0,0,8396800,8320,8388736,8388737,1,8396801,8321,8321,128,8396929,129,1,8192,8388609,8193,8396928,8388737,8193,8320,8388608,8396801,128,8388608,8192,8396928), k = new Array(256,34078976,34078720,1107296512,524288,256,1073741824,34078720,1074266368,524288,33554688,1074266368,1107296512,1107820544,524544,1073741824,33554432,1074266112,1074266112,0,1073742080,1107820800,1107820800,33554688,1107820544,1073742080,0,1107296256,34078976,33554432,1107296256,524544,524288,1107296512,256,33554432,1073741824,34078720,1107296512,1074266368,33554688,1073741824,1107820544,34078976,1074266368,256,33554432,1107820544,1107820800,524544,1107296256,1107820800,34078720,0,1074266112,1107296256,524544,33554688,1073742080,524288,0,1074266112,34078976,1073742080), T = new Array(536870928,541065216,16384,541081616,541065216,16,541081616,4194304,536887296,4210704,4194304,536870928,4194320,536887296,536870912,16400,0,4194320,536887312,16384,4210688,536887312,16,541065232,541065232,0,4210704,541081600,16400,4210688,541081600,536870912,536887296,16,541065232,4210688,541081616,4194304,16400,536870928,4194304,536887296,536870912,16400,536870928,541081616,4210688,541065216,4210704,541081600,0,541065232,16,16384,541065216,4210704,16384,4194320,536887312,0,541081600,536870912,4194320,536887312), A = new Array(2097152,69206018,67110914,0,2048,67110914,2099202,69208064,69208066,2097152,0,67108866,2,67108864,69206018,2050,67110912,2099202,2097154,67110912,67108866,69206016,69208064,2097154,69206016,2048,2050,69208066,2099200,2,67108864,2099200,67108864,2099200,2097152,67110914,67110914,69206018,69206018,2,2097154,67108864,67110912,2097152,69208064,2050,2099202,69208064,2050,67108866,69208066,69206016,2099200,0,2,69208066,0,2099202,69206016,2048,67108866,67110912,2048,2097154), L = new Array(268439616,4096,262144,268701760,268435456,268439616,64,268435456,262208,268697600,268701760,266240,268701696,266304,4096,64,268697600,268435520,268439552,4160,266240,262208,268697664,268701696,4160,0,0,268697664,268435520,268439552,266304,262144,266304,262144,268701696,4096,64,268697664,4096,266304,268439552,64,268435520,268697600,268697664,268435456,262144,268439616,0,268701760,262208,268435520,268697600,268439552,268439616,0,268701760,266240,266240,4160,4160,262208,268435456,268701696), S = function(t) {
. q3 G) n+ C. [! ~: S, I for (var e, i, n, a = new Array(0,4,536870912,536870916,65536,65540,536936448,536936452,512,516,536871424,536871428,66048,66052,536936960,536936964), s = new Array(0,1,1048576,1048577,67108864,67108865,68157440,68157441,256,257,1048832,1048833,67109120,67109121,68157696,68157697), o = new Array(0,8,2048,2056,16777216,16777224,16779264,16779272,0,8,2048,2056,16777216,16777224,16779264,16779272), r = new Array(0,2097152,134217728,136314880,8192,2105344,134225920,136323072,131072,2228224,134348800,136445952,139264,2236416,134356992,136454144), c = new Array(0,262144,16,262160,0,262144,16,262160,4096,266240,4112,266256,4096,266240,4112,266256), l = new Array(0,1024,32,1056,0,1024,32,1056,33554432,33555456,33554464,33555488,33554432,33555456,33554464,33555488), u = new Array(0,268435456,524288,268959744,2,268435458,524290,268959746,0,268435456,524288,268959744,2,268435458,524290,268959746), d = new Array(0,65536,2048,67584,536870912,536936448,536872960,536938496,131072,196608,133120,198656,537001984,537067520,537004032,537069568), h = new Array(0,262144,0,262144,2,262146,2,262146,33554432,33816576,33554432,33816576,33554434,33816578,33554434,33816578), p = new Array(0,268435456,8,268435464,0,268435456,8,268435464,1024,268436480,1032,268436488,1024,268436480,1032,268436488), f = new Array(0,32,0,32,1048576,1048608,1048576,1048608,8192,8224,8192,8224,1056768,1056800,1056768,1056800), v = new Array(0,16777216,512,16777728,2097152,18874368,2097664,18874880,67108864,83886080,67109376,83886592,69206016,85983232,69206528,85983744), m = new Array(0,4096,134217728,134221824,524288,528384,134742016,134746112,16,4112,134217744,134221840,524304,528400,134742032,134746128), g = new Array(0,4,256,260,0,4,256,260,1,5,257,261,1,5,257,261), b = t.length > 8 ? 3 : 1, y = new Array(32 * b), _ = new Array(0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0), C = 0, w = 0, x = 0; x < b; x++) {
/ I7 t) r1 p% u var k = t.charCodeAt(C++) << 24 | t.charCodeAt(C++) << 16 | t.charCodeAt(C++) << 8 | t.charCodeAt(C++)* _3 P: R3 k2 K% L. G
, T = t.charCodeAt(C++) << 24 | t.charCodeAt(C++) << 16 | t.charCodeAt(C++) << 8 | t.charCodeAt(C++);
6 p& N( K; S' U$ t8 w k ^= (n = 252645135 & (k >>> 4 ^ T)) << 4,8 o5 C1 {$ L$ y
k ^= n = 65535 & ((T ^= n) >>> -16 ^ k),! N+ ~) j9 o1 C; s
k ^= (n = 858993459 & (k >>> 2 ^ (T ^= n << -16))) << 2,. v8 T: w; R8 G9 x' t
k ^= n = 65535 & ((T ^= n) >>> -16 ^ k),) [( c g3 G" _' t3 r) i9 \
k ^= (n = 1431655765 & (k >>> 1 ^ (T ^= n << -16))) << 1,
) u& f5 q0 B* u& z k ^= n = 16711935 & ((T ^= n) >>> 8 ^ k),4 J! \6 }1 `& B* y/ c: j
n = (k ^= (n = 1431655765 & (k >>> 1 ^ (T ^= n << 8))) << 1) << 8 | (T ^= n) >>> 20 & 240,! _& V2 [: s, T1 d9 Z m3 ^
k = T << 24 | T << 8 & 16711680 | T >>> 8 & 65280 | T >>> 24 & 240,: o6 r: J8 m+ L" b) m2 C
T = n;
) S( i( Z4 R. l& G3 i; } for (var A = 0; A < _.length; A++)9 d/ s$ B& ?) X+ b' F Y8 \
_[A] ? (k = k << 2 | k >>> 26,1 |% k0 [$ }* }' j# J, q
T = T << 2 | T >>> 26) : (k = k << 1 | k >>> 27,% U0 o x/ m( p" M0 l" e8 C
T = T << 1 | T >>> 27),
1 S8 @0 w$ n8 d3 y0 h8 G T &= -15,% @+ f: C+ z4 b. B4 b {
e = a[(k &= -15) >>> 28] | s[k >>> 24 & 15] | o[k >>> 20 & 15] | r[k >>> 16 & 15] | c[k >>> 12 & 15] | l[k >>> 8 & 15] | u[k >>> 4 & 15],9 G7 t K1 X) W d4 Z7 N
i = d[T >>> 28] | h[T >>> 24 & 15] | p[T >>> 20 & 15] | f[T >>> 16 & 15] | v[T >>> 12 & 15] | m[T >>> 8 & 15] | g[T >>> 4 & 15],
* S1 ?: o) l2 F n = 65535 & (i >>> 16 ^ e),
, o1 ~" n# t9 _' | y[w++] = e ^ n,' o7 T) \2 p) C) W! t" A
y[w++] = i ^ n << 16
) ?" a3 r' ^! ?4 A0 a$ q6 g' E: u0 l }
$ x6 U$ w; m/ N1 J1 {% L2 ~ return y$ i) p2 [& }! {) r. j" u
}(t), z = 0, B = e.length, I = 0, j = 32 == S.length ? 3 : 9;
, e( z) i% k4 b1 j" ~7 w p = 3 == j ? i ? new Array(0,32,2) : new Array(30,-2,-2) : i ? new Array(0,32,2,62,30,-2,64,96,2) : new Array(94,62,-2,32,64,2,30,-2,-2),! A" x& @4 Z E+ O4 ~; }0 D, P& E+ `
2 == s ? e += " " : 1 == s ? i && (c = 8 - B % 8,4 j, M9 |6 o1 H4 W, W
e += String.fromCharCode(c, c, c, c, c, c, c, c),
v' D7 ?6 K/ p9 F3 O! j6 M 8 === c && (B += 8)) : s || (e += "\0\0\0\0\0\0\0\0");( N9 S" A( S0 d
var F = ""
" Q: Q1 ?8 r0 g$ T( i , $ = "";0 _+ k! R' r8 }( j: ~, d0 M
for (1 == n && (f = a.charCodeAt(z++) << 24 | a.charCodeAt(z++) << 16 | a.charCodeAt(z++) << 8 | a.charCodeAt(z++),
0 {" k m1 y, @) u m = a.charCodeAt(z++) << 24 | a.charCodeAt(z++) << 16 | a.charCodeAt(z++) << 8 | a.charCodeAt(z++),' i. R6 R4 x# s4 F7 e9 S9 G
z = 0); z < B; ) {
. L9 o3 N7 Y L4 D for (d = e.charCodeAt(z++) << 24 | e.charCodeAt(z++) << 16 | e.charCodeAt(z++) << 8 | e.charCodeAt(z++),2 h) F( @% H3 I" n
h = e.charCodeAt(z++) << 24 | e.charCodeAt(z++) << 16 | e.charCodeAt(z++) << 8 | e.charCodeAt(z++),! Z1 V1 ?4 f5 c* ?" G0 w' U
1 == n && (i ? (d ^= f,3 h/ I8 F7 A; t
h ^= m) : (v = f," c# `& O% Q6 C J
g = m,
0 }: q8 d& O( D2 `( j f = d,3 _. u* v4 q* e
m = h)),
f7 p8 v6 x$ n" y3 e d ^= (c = 252645135 & (d >>> 4 ^ h)) << 4,
% _2 }& h( Z$ X' L6 l d ^= (c = 65535 & (d >>> 16 ^ (h ^= c))) << 16,& B( E0 X! @9 U9 O8 u
d ^= c = 858993459 & ((h ^= c) >>> 2 ^ d),
- j" n0 t0 L3 D6 `8 o+ H5 V. t d ^= c = 16711935 & ((h ^= c << 2) >>> 8 ^ d),; ?) F6 `8 H9 ?, S7 w5 k, K
d = (d ^= (c = 1431655765 & (d >>> 1 ^ (h ^= c << 8))) << 1) << 1 | d >>> 31,
v% J+ @: U l/ U- l# V h = (h ^= c) << 1 | h >>> 31,
! z& ^1 a k/ U, B) r% n r = 0; r < j; r += 3) {
6 [+ q! @: z8 H for (b = p[r + 1],# F0 P) Q- c* f2 Q& _ J7 J. @
y = p[r + 2],
5 y% o* v8 a& Y9 }2 ?5 Z( | o = p[r]; o != b; o += y)9 s$ M7 p0 W! G' l) K$ B
l = h ^ S[o],$ ~4 c0 |. v" h7 I# @$ q
u = (h >>> 4 | h << 28) ^ S[o + 1],
% ?- y2 c& t3 `! e5 K c = d,
& Y1 @- x2 l6 h" @2 z$ g d = h,7 r- k d4 }$ |
h = c ^ (C[l >>> 24 & 63] | x[l >>> 16 & 63] | T[l >>> 8 & 63] | L[63 & l] | _[u >>> 24 & 63] | w[u >>> 16 & 63] | k[u >>> 8 & 63] | A[63 & u]);
5 _( X' q" E4 r# | c = d,
C, j# r6 r1 B; Z8 o( V% e d = h,- q1 \& Q/ q& ^! l/ i
h = c8 @0 _$ U" ?" }) a+ P
}
3 G( y, G" L+ [$ w- Z0 {0 } h = h >>> 1 | h << 31,
& ~4 @( R q. w4 R4 O h ^= c = 1431655765 & ((d = d >>> 1 | d << 31) >>> 1 ^ h),5 P; m+ L/ Y9 ^: m; _
h ^= (c = 16711935 & (h >>> 8 ^ (d ^= c << 1))) << 8,. V5 r z% ~" ]: ?8 A: t
h ^= (c = 858993459 & (h >>> 2 ^ (d ^= c))) << 2,: v8 b: T( Z1 k+ G! W
h ^= c = 65535 & ((d ^= c) >>> 16 ^ h),7 A+ S. N Y7 g3 o: ~. Y
h ^= c = 252645135 & ((d ^= c << 16) >>> 4 ^ h),- t! J2 y* h; x% z9 K: v
d ^= c << 4,% u' B, ?( j# Q2 z4 u4 J5 W, v
1 == n && (i ? (f = d,# t! W& H# }. b! A n3 \
m = h) : (d ^= v, v3 ^$ j: x! ?8 P6 I
h ^= g)),) X5 \: t* G9 t) u
$ += String.fromCharCode(d >>> 24, d >>> 16 & 255, d >>> 8 & 255, 255 & d, h >>> 24, h >>> 16 & 255, h >>> 8 & 255, 255 & h),
, i0 v+ u+ S3 s& g, ~9 P* G/ @( g 512 == (I += 8) && (F += $,
. [% ]9 c& K5 O& a9 n1 s; [ $ = "",
# K; o4 I' e7 F/ {* x I = 0)) v7 {* S3 N8 C& R& C( j3 \
}
3 ]9 \* C( N& k+ o) ?0 f- @ if (F = (F += $).replace(/\0*$/g, ""),8 P/ M, r2 s ?" k9 a
!i) {
' J2 I" E; n$ f, z9 o" P) } if (1 === s) {
4 Z4 S+ E# w6 z5 m t var N = 0;- m$ l" v" @# t+ B8 {
(B = F.length) && (N = F.charCodeAt(B - 1)),
' k7 w% n4 C% z8 Z N <= 8 && (F = F.substring(0, B - N))! l) `* x( x; W# k7 i) s+ D. w
}
' ?9 _! v0 u `5 @ F = decodeURIComponent(escape(F))
: ]0 ]3 q9 A, @6 S* }; P" Y$ \3 f }! Y l- ` T1 N9 d2 A
return F0 g) Q9 n4 _3 `3 F
}/ H4 o; W; G9 X$ v% u
0 S4 t4 Z7 F% z1 ]* r- Y$ j6 h t% A y: l' W
现在,我们也找到了解密的js函数,也有了加密之后的数据。把这几段关键的JS代码抠出来做一个测试,这里我使用在线的工具,有ide当然更专业。先简单的做一个测试
. t0 [1 `1 ?2 y& w: b/ W' D# ?( D- A5 h% [- e; |# z1 G
function decrypt_func(t) {- r; s) Z. T$ s4 @5 e- K1 F
return JSON.parse(s("5e5062e82f15fe4ca9d24bc5", window.atob(t), 0, 0, "012345677890123", 1))
7 D: w/ w) G! _* F; [}, H2 c- z; d' U- ?
! X5 Z& s7 L9 o3 [5 [encrypt_data = ""
' m; s: d$ h E$ O0 V//这个加密的数据我这里就不提供了,测试的话打开网站请自提一下* b0 r4 J* {; V) A
data = decrypt_func(encrypt_data)
+ k4 a$ x& Z5 Uconsole.log(JSON.stringify(data))
. v: j; a. Z8 w6 C% B# Q9 D( M+ G2 _! g6 s
加密的那个s函数我也贴在上面了,别落下,然后我们看看测试效果,这…这…这不就是那个自行车吗?
2 D& P7 [! O. t4 Y# T# d7 B, a4 R" j, I0 o7 C
! C+ ~+ E, e- @& Z, r4 U) S+ Q后来吃完饭,我也把完整的代码亲手交给了她!
; [ Y, U/ z8 L% N0 u4 J! B0 M
" F0 `: ~0 z5 |3 V 好了,到这里又到了跟大家说再见的时候了。我只是一个会写爬虫的段子手而已,一个希望有朝一日能够实现财富自由,能够早日荣归故里的游子罢了。希望我的文章能带给您知识,带给您帮助,带给您欢笑!同时也谢谢您能抽出宝贵的时间阅读,创作不易,如果您喜欢的话,点个赞再走吧。您的支持是我创作的动力,希望今后能带给大家更多优质的文章
( K9 L# Z' k3 y U3 M8 c/ [————————————————
2 D& [/ ^& g! Q B5 w8 @ G7 a) P$ Y版权声明:本文为CSDN博主「似繁星跌入梦」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。: E; f3 g) q* |+ S' `
原文链接:https://blog.csdn.net/qiulin_wu/article/details/105954687
- t' e& v* @' P6 l8 Y+ h% C- V( _. }* r$ b
4 u. {4 L5 I) D: A& t: f- r |