★我要吧★

 找回密码
 注册[Register]
搜索
qq空间相册密码查看为什么登陆后需要激活无法注册?

[分享] QQ空间爬取教程

[复制链接]
发表于 2024-5-15 02:00:52 | 显示全部楼层 |阅读模式
selenium模拟登录& @# d  M% d! |
QQ空间的反爬做的相对较好,而且由于好友权限的原因,我们要先登录后再进行说说等信息的获取4 G1 d9 J9 ~' K, a
4 k9 l/ t' v. m; h  j5 Q% L5 s
selenium是获取登录cookies的一大利器,非常方便
) g5 l: w/ O5 ]4 M8 E
/ s$ }, x% s9 |- g) q4 q4 |
7 q$ b8 v5 `% R+ c
2 h: @& c$ }- I4 ]1 N; Z, p4 {" v在空间的登陆界面可以观察到,登录的窗口与背景窗口是分开的,所以我们需要先切换框架0 ]( l, W$ _6 m" F, t  I* X6 J
) j& ~' Y7 x5 ~! o/ H# I' V
切换窗口后定位到账号密码登录元素的位置后点击5 ~; u0 F. E6 I& |7 i8 q
5 ~+ A  H, d  d
0 |: K% a4 @6 v' y" A) [$ x+ S

3 m1 \* u: i. d1 Z3 j. i6 }/ W, g使用send_keys函数把账号和密码写入对应位置后定位登录元素后点击,这里使用自带的get_cookies函数获取到cookies,但是这个cookies需要过滤一下,具体操作看以下代码5 b; E% q  ~1 k

7 `/ f3 J& M* {( \代码为类的部分节选,完整代码在最后,未声明的变量皆为类的成员变量
* ?/ g9 T% h0 L: Z. Z! [) f4 c3 K6 @# z7 |+ h5 J! B; U
de login_func(self,z):/ l3 w' \# o! m
browser = webdriver.Chrome()% H' l# ^, ~( Y5 C( k1 Q2 Q
browser.maximize_window()+ K7 S' j! J; q- t; e  Z. n5 w
browser.get(self.login_url)
, U2 h9 c! S1 h, F5 a4 W time.sleep(1.2)
, B2 q$ o! \' W% y  ?4 v browser.switch_to.frame('login_frame')
& v2 q: c+ D0 m! u browser.find_element_by_id('switcher_plogin').click(); o1 p; p0 g* N7 y
time.sleep(1)
. V/ I/ ^+ G* o( X& H3 Z8 K browser.find_element_by_id('u').send_keys(self.number)% U2 H) V1 ^( X9 i' E. E
browser.find_element_by_id('p').send_keys(self.password)! |5 z6 \8 }$ n0 U2 r
time.sleep(1)
  d7 _. j$ a$ [. M" M) V* [ browser.find_element_by_id('login_button').click()" M5 o! f! i; H, l6 X
time.sleep(1)
7 N" a- I1 }% V: f cookies_list = browser.get_cookies()
( m! l- z% ^6 y- Q2 y
/ _& s1 X7 v4 {2 Q% T for cookie in cookies_list:8 z- R/ P6 s# P0 n6 Q( Y# d$ C
if 'name' in cookie and 'value' in cookie:; H2 u8 A; N. a: N4 a9 [4 G5 j
self.cookies[cookie['name']] = cookie['value']4 O) p; |4 e9 }" Z) D/ f
# print(self.cookies)
# A2 `+ x( E3 {4 R. f with open('cookie_dict_{}.txt'.format(z),'w') as f: # 这里是为了一次性多刷几次cookies建立一个cookies池,便于加快爬虫速度,后面再提6 T4 B* ?5 q) Q' x/ j
json.dump(self.cookies,f)+ D/ o" k% ^) H/ p: F5 I
# browser.close(): i* [4 r- Q6 f5 |& K# E9 P9 h

7 ~4 {" j* R+ F5 v, b1. x9 g& `; ~9 X# s" A2 ~# ]
24 Y9 s- I9 [+ W  C9 G
3
& S) z, R' c0 j4
1 I8 N+ M5 c" `5% S9 k+ h& v5 |# {" B
6& ^9 Q* j% U9 Q
7
  E: u; b# x, a# g6 f8: j3 L8 w2 K. f' }3 O* a! z9 P
9
- ~$ P$ n+ ~( ]8 M( @  O10
. p- K. j6 ~1 t9 W2 I11% P4 B: z, _# y3 r6 g: m% b
12
9 B0 }5 e7 X' g5 w3 S13
0 b0 `& h+ _) A, ]$ S- |; r+ s/ r& R! D7 G; y
14 15
* o) z+ h4 |! t- p% s7 z' G5 @( L4 W( s6 J
16 17
& M3 Y5 d& T0 G( T7 @9 W18
9 D+ H7 \' ^$ z6 u  i19
. R) z  C; X% Y, p+ ~20
$ {- B2 t- h) F21  z  U$ l9 u- w7 A' I! b) Q0 _+ _& ?' y
229 u( \7 U- n4 Y
说说内容获取
5 R5 f: ?9 ~9 ?0 e: s% f1 Y. O) C0 T在打开开发者工具后,在众多XHR对象中发现emotion_cgi......里面的msglist即是说说的内容! P; R+ J) u, c& a
  }8 B. Y3 U; F8 P4 N( b
4 f0 K6 g# d- O9 g/ p9 f$ l1 T

9 r. t8 S, {4 {. \+ B1 A8 x. Y
; p: e0 g2 G! ^0 N/ [3 ^6 ^2 L, m5 m4 U0 \# m7 x$ n8 f
这里的msglist是个列表,里面有0-20条不等的说说,可能跟空间发的说说的形式问题相关,至多不超过20条
( @* P& U* r* s6 {/ v# l
' F1 h# }9 I/ O" g稍微猜测一下这里的参数的含义,一眼明了的我就不说了,我不清楚的也没有肆意揣度8 H; N1 P% d- g
# E& ?2 w, D$ a2 \
cmtnum 转发数
% G, Q" E' a0 q8 U+ G
8 ?) [3 G. a5 J, n3 [( bcommentlist 评论列表,里面是每条说说
: `/ `0 Y) h4 R+ j
1 V# _8 v$ D' {! \( v4 h: e" S的内容conlist 内容的一个列表,里面有两个参数,一个是内容一个不知道有啥作用,取内容的话直接取下面的内容也是一样的, H" B( s- z3 R

' Z+ Y. E' C! l5 ]& ~* x: tcreated_time 说说发表的时间戳. J  f6 b$ z' C4 e3 v6 v% g* j* ]
9 Q: i1 z' x7 h7 D2 P( f$ u
isEditable 是否编辑过
/ A( G$ Z/ O5 f5 ?" `5 Q- v$ v0 l4 i6 ]/ S/ a
lbs 位置信息* o  }) N* ~- L9 C, n: V1 M; \
* q- [8 v$ H# A8 [
name 你给的备注,没备注就是昵称" [. n) A5 @% u8 g9 x7 E1 P

$ B7 X( w% O) e' F+ _  B, kpic 如果发的说说有图片则在这个键下面,但是如果没有图片则没有这个键
2 B8 j4 A2 J$ n7 ^3 h/ v) Q
6 G: z; R  ^+ k, B. ?pictotal 图片数量,没有图片则没有这个键( ~8 W0 e9 e  ?1 C- a  S

' ~! J' R9 O- f9 d; M$ V. t0 Nrt_sum 猜测是转发数量
, F3 D, ~" r) f2 V/ t( X+ F: y1 t# q+ A
/ V. A* i% S$ [source_appid 说说来自的app标识; H  j7 E; V" M% I3 G

( z4 e  N% e1 Msource_name 说说来自的设备名称
9 |: ^& O/ t. }0 `% l/ N" w& [7 t) r$ N% S3 J7 j1 @' f- V
source_url 说说来自的网址
. k2 }8 f3 n8 l8 m8 s
" p2 q( C% d6 X' N6 _+ l3 @3 z2 vtid这个是每个说说独一无二的标识,可能是根据某些变量使用特定的算法得出的,直接使用即可
' T) o, s' X3 H  k: B* A" t7 C- ]
5 s6 B8 H$ X8 A$ y: b8 o# _uin 该说说的作者QQ  [2 B* k" n! ]4 r

# m) ]: i  J: N+ l当然如果是转发的说说,这里还会多别的一些键值,我这里未对转发说说进行处理,只是单纯地取出该QQ转发时发送的内容,有兴趣的朋友可以加以改进5 U. I, G& r2 n! C! s
0 I; \+ f5 E9 n# U/ i6 l/ v
下面我们看一下这个内容的获取网址构成
- [" c2 R# e5 ]% [+ H; [. L" b6 a, w5 j' [) S6 P( D/ }
在Headers选项中可以看网址的构成参数
0 A! v, `9 _, N$ j* l& \5 i- c- q0 @$ L! a/ M
经过尝试发现,uin后面对应目标QQ号,sort可能对应排序方式,我采取的默认值0,pos这是个关键参数,其改变决定了返回数据的范围,num是返回的说说数量,我选用的是默认值,不知道增大会有什么变化,读者可以尝试
$ Z. a3 m1 w0 L: Z8 A; ?  Y1 B- C3 M& r1 q  v
最后一个关键参数是g_tk,这是个加密参数,有了这个才能正确登录: U1 ~+ P: h& j5 W+ f

& Z$ e. ]+ ~3 i$ Z
7 M% B/ G6 }$ x' n7 K+ m) M- E, w0 ]
+ k* T% f1 v' a2 _' S) t" R破解g_tk4 ~# N2 q8 l4 ?* }. X& L
网上的搜索发现是js,破解的方法见下图& Q( t. q# h. b6 H/ u2 L" O
' [% {- v* f( ^2 ]7 {& _# q" L9 U4 b
随意点开一个人的空间,进行如下操作
; T6 L; l$ {" q+ V& ~/ G) X8 p
; Z& B6 Z6 t; ?" L
9 b( P/ ~' \/ ~- o
+ _- ?& \: k( T* t# S" ~搜索g_tk=后面的关键词
( G6 F& P8 F0 C" Q
1 r5 P- z/ T- s/ ]4 D  G
6 H! X' S+ v+ Z' c" F' Y9 j$ J" f9 \9 {" n+ z
找到对应的函数,这里的函数读一下之后将其转成对应的python语言即可7 T. }! j  N$ G5 ^$ x# v
5 n" U$ M% h; ^8 P  K" h( ^5 `
def get_g_tk(self):7 v. I( m5 W3 V9 L
p_skey = self.cookies['p_skey']
) z- h$ e& @0 g( k7 @2 M7 N6 h t = 5381; C% }+ _1 ^& a7 o. i
for i in p_skey:
5 }1 u7 R. x' p3 Q! g, s t += (t<<5) + ord(i)' ]- [. U: ?% O. O5 z. e
return t & 2147483647
- v7 a3 U  A8 K% v; L) b8 ]3 s1) o! l2 P1 S7 d3 ?+ U7 ^5 |
29 l" b3 O. S$ |1 n: r+ e
3
8 W' w. r' T% i: [+ p5 H1 ^4
; n6 b( ?# `1 [" m. |5+ x% P6 v; g! A! R
6
+ b3 d: j; f* G* M  H说说的评论获取
1 _  b& _9 F/ O9 p  A. `这里没什么好说的,数据返回是跟说说一起的,在commentlist的键里面,里面的键值对和外面的类似,这里就不赘述了,值得一提的是,外面的cmtnum返回的评论数是指单独的回复数量,也就是跟楼的评论数量不被统计,跟楼的评论在每条父评论的里面,对应键list_39 b( R' z8 a/ a$ v. c) Q3 D0 }
4 `+ s7 x7 w+ K* H) O/ `

& Z& a; u' k" ^& y2 z( r7 j3 D& R; ]$ o* x9 Q
说说的点赞人获取, E, N3 u; _; Q& P" n

4 t: |. L9 A9 V9 v* k  J
# W% R' V9 |6 u5 b; r8 |  q& ~框内可以点击,点击后
* ^! X) |% W1 y0 m/ G2 b
" \0 b" X; E" @( \) [. m3 \8 `' I. e1 m: t. `
出现
/ ^$ u6 u2 M4 _. o同时右边出现一个
* h7 u# n: C( B  N1 F# B& B5 V% [6 L* h

( B, R. j! z7 K/ ?  h( q& d, W# m8 r7 r, k. j2 |" {1 t
这里对应的内容为  X2 R8 c& T2 t) w7 H
4 o# E6 b& x  T1 C* V
is_dolike 我是否点赞了
8 d8 p: ?9 w3 d; H; d) g
' b3 x7 B( y0 q2 [2 G5 d1 dlike_uin_info 点赞这条说说的朋友的信息(除我以外3 Z+ D: a. U  L$ @

( |8 P) l# u/ b% G" {total_number 总共的点赞数量
' Z; y% F  f) C- e4 v, C* U3 `% t, `, X; K- Y) |0 A
每位点赞好友里面还有一些信息,我这里就没有赘述,那些键值都看得懂, I  n0 q0 p2 ^% n; \: Z* A* U
  o' H% n( B: a( k( \' L+ F3 x4 l' ?& C
url参数构成
) P% h  Y9 O" c0 U9 t# M! V那么还需要知道的就是url的构成,老方法,先看headers
* N* l: V- {+ c* ?* R+ W- }) A* Z/ i$ e. }. L8 B( j

$ N+ H( Q3 Z6 T( b$ F
; K3 m! i4 m6 y% x5 y) B那tid在哪里呢
. U0 Z' C' D  k0 x: H/ Q' O
1 B: B9 o# Y! h4 E) f, d( t. f9 ^之前的msglist里每条说说底下对应都存在一条tid,这里就是它的用武之地了!
* k5 V$ u& u' `# m
2 i' c1 i  N$ M7 j6 Y好友列表获取% t' h2 B) i; Z; u
我在网上看到过很多个版本
6 Q, s6 t7 y# a/ C6 D) @- ?- J. L9 j5 V: n; _- B4 d
我自己也都尝试了一下,以下的版本获取到的好友信息与QQ好友是最一致的
# y4 q: M$ ?2 ~7 d+ i: p7 Z- x8 ?% y( J
进入自己的空间后在设置中点权限设置4 r6 y! C9 W" Y) Q1 N7 [

3 u: {- h4 c& O: S5 b# E; Z" L3 g3 H1 v3 q

  k9 P- M0 {3 F3 c; B
, t+ x- h9 U$ Z' H2 W& W0 f& G
9 d1 z7 w) D5 r) T0 [找到对应的项,friendlist里面即是,但是只有50条,如果你点开了xxx个QQ好友并向下滚动后查看url构成4 `& ?4 B' m3 Q+ c% d' T) ~  u* d

1 t& Z& C* g$ d就会发现
- N* |. v4 j" h. z) k* q" p
" B3 x! l1 n- \, ?, c
5 ^& e3 M" m" g/ F, s; L& b4 J. `3 `
offset偏移量用来查看更多的好友4 n  s( t+ i% _
- L6 u9 h$ w4 y) f" a& h
,如果是最后一页,返回的字典中的键end的值为1
' Z/ i: P* _! w, ?+ t: K: D
  p4 L7 R+ Q# Q, W& g数据库的存储
  e6 X8 u7 b4 Q/ H& W由于对数据库的使用不是十分熟练,这里单纯只是为了存一下,有很多弊端,例如图片的存储9 R. o) j& E" P4 |( n* V
5 Y; F- q9 E1 ^: B3 l7 P+ x
而且用的很丑陋,这段代码可以忽略
1 F3 Y7 P  \3 s! F; t; ^( C
  l7 h9 S% V0 y; `$ v4 v4 `def check_exist(self,uid):) T/ y% z$ Q; t6 ?" s3 {
cursor = self.conn.cursor()
7 m' T" u5 D5 w0 B1 ? cursor.execute(“show databases”)" p" a3 W$ B/ D: V! j2 u
content = [i[0] for i in cursor.fetchall()]& l- S& {3 C( n
if uid not in content:6 L" ~$ [9 }. t% j% E8 Y
cursor.execute('create database '{}';'.format(uid))
( Q$ v+ t" f* {3 U6 |, l; j& x cursor.execute('use '{}';'.format(uid))8 H" N- H+ [1 j$ l
msg = '''6 U( d0 c0 Z& T, L* k
创建表 msg6 C' b1 h$ w# C* r

, o- w4 R$ S' b) H  U& X id text,* U& h4 t3 X$ }" y
name char(100),, p) E4 s6 w" H" }
content TEXT,/ y$ @  ~, L" _  E
createtime timestamp,; q3 G0 g. g( s+ I2 Y6 L/ M5 S9 D+ R0 a
tid char(32),
+ o: Z& K1 H. Z. W location char(32),
; t! u5 v  c. `& R6 j posx int(20),
5 Y5 p. @6 C5 r" \( F5 e4 I7 q6 ]  r posy int(20),- t: C! X7 h2 e% E: a* C/ G
comment_num int(11),
& U, J+ T0 J1 x6 l like_num int(11),
( g% j7 t$ F2 z: t6 v2 ^) I+ H pic_url TEXT,
( N/ g; V1 P6 w( u pic_num int,
9 ^5 h2 O, F2 [6 {# a+ ^ source_appidchar(32),4 K7 A% Y# F+ [7 r& B+ H* j2 K
source_name char(32),
7 r4 x# ?2 _9 W9 l is_tran char,
% Y( S$ u7 Z* v) n2 ^4 W* } trans_num char(32),
9 K: B; [0 |( \8 P# q5 x1 A: |5 w trans_content TEXT9 m/ b# i. h1 F
);  v8 B0 b- _. Q3 B
'''/ c. P2 }) A6 Z; \+ v3 \
cursor.execute(msg)
& z. e& G( R. ] cmt = '''
- _: z5 L; _3 K2 |1 } create table comment
3 l& G  u$ B) H4 X% w4 O3 I7 z+ |6 J! C$ v/ g, g3 p
tid char(32),
$ L0 a* X8 A- N$ ] id text,, A4 p( q$ ]( V
name char(100),4 C9 b0 G5 T* z' `
content TEXT,
7 s& b& a) a) S& V createtime timestamp,
& T$ s7 f  L- V7 d  H  h reply TEXT, Y3 K7 h" [; v
- a% d) _5 l$ u
'''- K" x$ A7 p9 o3 Y& }" w/ ~
cursor.execute(cmt)
2 U7 i, _  r3 u: v like_table='''+ G# W; }9 x9 m% I. D
create table like_table
5 T3 t) T( V3 A% B! c4 y7 W
+ ]0 K8 r1 F" {3 c3 x9 E tid char(32),
! d+ v( l; T* _: h/ f" A id text,6 x8 i- p8 v! E5 {
name char(100),# \# N+ c- L) u0 l
addr char(32),; B' u9 J4 u$ t
constellation char(32)、; Y! I5 Z7 Q+ H% i7 m3 C. U
gender char(4)、
" N4 r% J* A" Z$ H+ A. i$ i( X; Lif_qq_friend int(1)、
, d3 C: N  A2 w: |7 T; o5 rif_special_care int(1)、
) r) B! }" ^; \) w- H/ ^is_special_vip int(1)、  N( o4 R: C) [1 K7 Q3 q0 I
portrait TEXT
. D" h; I8 F7 B# K' e' I! h) g$ V( T$ Q0 X8 @6 j9 n( i9 k5 p
'''
7 j0 w8 Q2 }  w" u! d7 z  q cursor.execute(like_table)
/ y0 n1 E. c0 p, n; h self.conn.commit()
! o* Z" E8 p, w; C$ b1 i4 E6 d4 d return 1" P& G: q. c) S& y4 D+ ]% ~
else:& k( Y  n9 W1 }! I
return 0/ F: b% `* K" N9 r
1 B) m+ y' Q) ?5 x
————————————————
# w9 h% L$ `8 Z1 _/ o+ X  t
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

QQ|手机版|小黑屋|☆我要吧☆ ( 豫ICP备13016831号-1 )

GMT+8, 2024-6-16 07:59 , Processed in 0.069942 second(s), 19 queries .

Powered by abc369 X3.4

© 2001-2023 abc369.

快速回复 返回顶部 返回列表