数学建模社区-数学中国

标题: Python爬虫常用库总结 [打印本页]

作者: 杨利霞    时间: 2021-7-8 14:55
标题: Python爬虫常用库总结
/ F$ d1 p- v# A( z
Python爬虫常用库总结
7 d7 U* [9 _. l+ A' e( @文章目录
+ k) a8 p5 f$ X* f, u( Yrequests
( V: j' _5 W4 e+ G+ d% z+ ?requests基础
9 W+ _/ ^! a- X! `) ~requests模块发送get请求
# v. w6 z/ q/ _9 J  i0 Hresponse响应对象
( n& P( ]; j. S7 l* K( R. c7 oresponse.text 和response.content的区别
6 o& ^$ Z6 q/ r! s4 y' m8 I4 X% F解决中文乱码- Y5 ^2 t2 E( r
response响应对象的其它常用属性或方法+ Q" R4 h& J4 K9 y0 w
requests实操
/ z. a; |4 ?( r, ]* Irequests模块发送请求0 v" ?0 I0 l6 c" B
发送带参数的请求
; ^: x$ a1 u4 b8 K# C) ?8 K+ U8 R8 ^超时参数timeout的使用4 u- t. d1 [, w4 N/ H
requests发送post请求的方法
& i/ |% E# c9 Q0 {# IBeautifulSoup1 g0 f0 r: @! L% \/ a+ E8 A
常见解释器的优缺点
! n8 t( q; E/ `常用操作
! C; c1 `+ P  f几个简单的浏览结构化数据的方法8 z! i4 X6 D* t5 ]1 `; d
从文档中找到所有的< a>标签的链接# M% g8 J) b& H' D; t: ?2 @
在文档中获取所有的文字内容8 ?" S8 F$ C8 ^( |, {* R
通过标签和属性获取2 z5 R5 a- M  f% `) [1 D
Name属性# W$ h+ f+ y: B. Q1 N9 \4 r
多个属性
6 c/ R7 }+ H% J: e8 w& ~8 M多值属性
2 A# z9 p6 Z) ]可以遍历的字符串" A8 o# W9 g$ M3 c  g% m/ M5 r
注释及特殊字符串; L+ J/ g- K' Z' e9 C3 [8 [
遍历文档树
) g% d1 f) w* R子节点
* i7 b: \7 w- ofind_all方法0 [# c8 Z) \& s2 ?& n" v
.contents和.children. Z' L6 }, B( k7 C  D
selenium
7 Y* M5 @  J# g7 j& E' vselenium介绍5 X' _% |* d+ R
chrome浏览器的运行效果7 P" ]2 q8 `: g" {
phantomjs无界面浏览器的运行效果
& D  i" @+ S, wselenium的作用和工作原理
9 o# X7 d0 S& Q- W5 p" ?selenium的安装以及简单使用
7 R1 b# O; L. d9 c2 q2 F- Vselenium的简单使用
" [, K, V0 A& glxml) a# J$ y& h: C9 Y! [
记得安装快速第三方库,Python经常需要安装第三方库,原始的下载速度很慢,使用国内的镜像就很快啦
- z' F0 u; n9 |8 T/ c: ~+ {8 p& G  W( d1 ?; N& A2 i6 @4 Z9 c; G" Z& C& `$ R

; ]* \- K8 w0 M/ p6 o) Z; y5 _pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple 包名
8 B- T" l+ y& x* w( Z% B. i1' T  ~7 f( f$ ], C2 D" o6 a
快速下载模块
1 n! {" ^% F% E4 t; r4 N0 V
: r# z+ f8 E4 U5 K3 k, M, k

3 Q: }/ x7 _) D' }  B3 R" }0 U官方网址:
. w( k& k4 b& Y& i' `2 D- D
+ I' k5 @! N$ `8 e

* j1 v9 b0 B' M4 ]) [Requests: 让 HTTP 服务人类
/ K  @) d8 L5 aBeautiful Soup 4.4.0 文档
% K+ k0 J" g5 i1 _Selenium官网: w5 J* L' q; i3 e: Q6 s( W  z9 c% ?
lxml - XML and HTML with Python
0 Y, x' \5 E6 Z3 e/ i6 b2 Q4 m7 |requests
: |2 a' u1 C8 I0 v3 d$ zrequests官方文档 https://docs.python-requests.org/zh_CN/latest/" ]9 W: P8 \4 |. a  W

  Y* Q# P9 N' s9 H5 ?" f

/ z% |9 c5 U5 W( N; Z$ V( w& K( ?
  V- U$ N( w0 C% }6 d
/ [) |* A- }3 j6 D- v) c- [

2 K- l' m# G% B$ B5 t进行爬虫,首先要对网址进行请求,这个时候就要用刀我们的requests模块了。requests是python的一个HTTP客户端库,跟urllib,urllib2类似。与urllib,urllib2相比,requests模块语法更加简单。正如他的官网所说:4 ^, P, B3 D2 e9 B% v8 B

& q0 Z, y+ Q! d
) L" b+ ^' t! K- F, i
$ [0 V; U" J5 k( S1 R7 ~
/ o0 }  }. `" C
requests模块介绍; y1 Q( W6 x. o. {# U

2 o% g0 B, r( H

7 ~0 h5 r5 s) ?8 b7 z) l% c发送http请求,获取响应数据
6 X9 A* q8 e; |2 q9 F2 w
2 _4 b, A" Q/ p( k/ }+ K

4 Z8 N5 v1 X' n$ A8 m. `requests模块是一个第三方模块,需要在你的python(虚拟)环境中额外安装' t, s0 K9 Z& W* S' B2 P

! y( \/ u- c" L& M9 g+ M

8 t( b9 C( c6 }6 z% J+ fpip/pip3 install requests3 U( q4 |- `5 |) X# P0 S6 L. ^

! v# N! m- }8 \3 i' R) [" ^% |5 S- U

8 O9 {/ O, L$ Prequests基础4 K5 q- m- {- y7 g) G, o' T
requests模块发送get请求
+ B2 \2 c$ \3 D% s#https://beishan.blog.csdn.net/
$ Z- E7 h; w: ]$ b  K& G0 D$ Q: S' rimport requests
9 W. L9 Z2 k  m) E/ G' x# k9 [; R# 目标url, n) n: l, M- j
url = 'https://www.baidu.com' ! h# u1 K. z6 s
# 向目标url发送get请求9 y! K* E) F6 W! K9 X2 G; ?: _
response = requests.get(url)
, |8 W# W, M1 E3 z6 j5 V! q# 打印响应内容( r) l7 J* I  `7 t
print(response.text)
3 g; e3 C9 ]1 M5 S" x  A1
8 O6 d9 T9 V0 j, W3 g$ }2$ _2 x5 M$ I: T* c4 e
3
- S; P7 p) G7 s- t4
# X' N0 v; q7 B- |1 i5; i3 S+ G& v  b/ W2 S& i: _
6
  A) b" r# a! I- e7
3 E' N& s, f, V! z8) E8 A2 ]& T6 Q
response响应对象
0 Y" F- K8 I' ]* z. S观察上边代码运行结果发现,有好多乱码;这是因为编解码使用的字符集不同早造成的;我们尝试使用下边的办法来解决中文乱码问题
) y& ]  P# _/ f6 b% K. m
; I  s4 b+ l+ Y* b

. _2 p! x8 U5 R8 o% {: R/ J+ pimport requests * w# B7 E+ M3 q) ^: S
url = 'https://www.baidu.com' 8 Z5 s1 a$ T! [  t3 U9 q* q, h
# 向目标url发送get请求
' c' R$ a) M! _8 b. Y/ Z0 nresponse = requests.get(url)
% s1 T+ F0 |; q: v+ Y* F: R/ I# 打印响应内容
/ ]! U: Z& U  Y7 v- ]  u6 E# print(response.text)
; ]$ N7 z, Q. y8 C. t7 r1 `print(response.content.decode()) # 注意这里!
0 c' Q3 D! N1 Q! W1- j# U' D% s$ u( @$ c
2" R9 K2 L: e9 f; r# t+ B* h
3! J9 j& ^  h$ e3 n. }4 S
49 s  D& l5 i: {+ J: N1 i1 }
50 A. Z5 D3 H% P0 C4 W
6
( @* t' d1 |6 W7; }) U7 K$ s9 j! m8 N  ?5 @( I
response.text是requests模块按照chardet模块推测出的编码字符集进行解码的结果
! {' R& h: }' }% J  d0 f网络传输的字符串都是bytes类型的,所以response.text = response.content.decode(‘推测出的编码字符集’)- O3 w5 s* H, ^- I! m
我们可以在网页源码中搜索charset,尝试参考该编码字符集,注意存在不准确的情况3 n4 \% P$ A4 l' Q
response.text 和response.content的区别  |0 y$ ?( X$ w1 V2 Z# M
response.text
" x! ~# F: R4 B类型:str3 f+ O' R, K1 w7 K6 |5 Q
解码类型: requests模块自动根据HTTP 头部对响应的编码作出有根据的推测,推测的文本编码2 W, z9 |" B1 f  Z6 x% u, \5 x
response.content* Y& O& R+ u  @- p# G/ `
类型:bytes
; d& y* H# s+ d* E2 X. U3 w; K解码类型: 没有指定
3 e2 ?3 S/ ]* e6 y/ g: U* Z) Y/ `解决中文乱码/ B1 a% ?  Y, W0 ]2 O! @
通过对response.content进行decode,来解决中文乱码
. N+ O. M) ^+ j+ u, {3 T/ N8 q1 s. E* y' q6 L; D4 n' @

; ?/ K  c' F" i$ Y6 q5 H% x. fresponse.content.decode() 默认utf-8
0 ^; O) T1 }$ f' hresponse.content.decode("GBK")
4 ?, }7 _% H* [) c7 W2 p常见的编码字符集
+ L$ C4 @8 q6 x* q$ D8 hutf-89 Y# J! d: p" V+ ?- `1 J+ |+ g
gbk8 Y& g  }$ Q# \! [+ x' I  [( x, r
gb2312
; X# V. @% \. U% X% l# w  D0 A& Mascii (读音:阿斯克码)6 D" M' V  w% s! U0 j
iso-8859-1
- q* {0 C$ e/ N9 {response响应对象的其它常用属性或方法
  J2 h! B# C8 ?2 h6 I#https://beishan.blog.csdn.net/
  N8 a! o9 d; H% u2 P# 1.2.3-response其它常用属性) l7 \/ k9 D+ y/ S' J; n5 `
import requests
0 m/ |( x7 h9 p' Y2 y7 w( `2 I) h) c2 k" C0 G

) E6 ^* b1 g  b) c0 P# 目标url
$ m. s! N0 u# o( \2 ~. {3 Jurl = 'https://www.baidu.com'
+ c/ h% ^, \3 e# T+ Z; d* y- k
. ^$ J) P- g8 X5 T) r4 R) U: q
7 }& W, g! x' P1 k# K! Y
# 向目标url发送get请求( G1 s) W4 R& c/ ?4 v, h0 F
response = requests.get(url)
! O9 P1 K4 U: G. C5 a) A$ }# D; v5 C! b

1 R: @+ Z9 ]' p! I# 打印响应内容
% E. f, ]( N3 B' P) R# s" J# print(response.text)
& _6 \- U0 S/ ^' k6 M9 p1 k# print(response.content.decode())                         # 注意这里!
. Q0 x1 W" Y2 lprint(response.url)                                                        # 打印响应的url
" T+ ^2 I, g  m, g( U. Xprint(response.status_code)                                        # 打印响应的状态码! c: J. l5 b2 \. G9 R0 z( g* h2 l
print(response.request.headers)                                # 打印响应对象的请求头
4 R4 @6 x* d  h* x+ n, \1 tprint(response.headers)                                                # 打印响应头
& [" V5 P" u/ |' z- M$ ]" Dprint(response.request._cookies)                        # 打印请求携带的cookies
7 }6 Z9 ]& Y3 K# N, Q. X* iprint(response.cookies)                                                # 打印响应中携带的cookies
9 P. Y  {. `7 i1
6 z% U3 T, L$ C9 w; i2% m; L3 h7 |1 G/ }- x7 j
3
* G$ d' B& `1 F+ h& I45 M3 @" R% {( u" E$ ~! f6 O
51 s& D) |" _5 N$ |5 B' r  |
6! W( v$ v* j4 b% B0 I8 E( j! P
7
% |3 j( J% @, m2 P) R- t8
& C- L; X- x4 X6 ?94 f$ j2 c8 f+ u$ }
10
5 G% H& _* J# ?4 O+ e. H11' O6 Y6 E- _7 e6 T0 j. o
12
7 C8 S! e% C* ?1 i: a: r, A13" i$ `% e* A* Y
14
: t7 h" j7 D: _, h15
- x! q$ H- S5 W7 u; u3 h16
4 d6 P( a1 L  o: S" M' c. }/ V/ t17
/ D5 _0 ~4 F  k& \9 `0 J; `4 {8 w18! F* m) r% ]+ O6 E) ?. ]0 o
19
, P& z7 l. b# z  c3 K- ^2 drequests实操; I. w8 e/ q3 D. g$ [, O& E- Q- m
requests模块发送请求% e# V4 Q& b6 X, T
发送带header的请求
$ p* t" ?1 }; f9 D+ F* B. K  f
0 r  T& J- R- w. X' J# Y
我们先写一个获取百度首页的代码
. J$ M3 O) E. S4 w4 U* i5 s) U5 z, [& A
! g/ ~! K0 B4 f( K, M+ O8 [
import requests
8 X2 d: i0 w6 C; g  `& Iurl = 'https://www.baidu.com'  I0 n' ~) G: v0 r# o
response = requests.get(url)6 i; G# D$ W7 E+ Z% F6 b  ]
print(response.content.decode())
7 E/ N! Y" L% K4 Z* u+ E; Z; W0 ]! q+ q# 打印响应对应请求的请求头信息2 c( |& _6 m/ r6 I: w" R1 l/ m
print(response.request.headers)
6 F8 @4 Y9 j" m6 Q1
, M# Q$ H% V0 x( v- t+ x# O2
) T8 Z! G4 _/ A% @" y( _" {' f* z3
/ D! l% H! C, _( i) [1 Q4
8 w" z2 @/ W0 p" U51 w& `5 S$ P. I
6
, M, g2 I2 b( r从浏览器中复制User-Agent,构造headers字典;完成下面的代码后,运行代码查看结果
: v$ ]$ D5 G" a$ S3 z# }+ f* A* h( N
. _" N6 j- i7 q3 P- @' Y; l
import requests, Y$ R. r4 @  x. v/ `4 E

- E1 W" n9 X0 U4 f
7 }9 M+ ]- A0 h4 e( N
url = 'https://www.baidu.com'
6 M3 r8 v" k! v7 V6 t* _. P8 C/ U* `( G

, \9 D3 B6 \' t8 X( t* kheaders = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}! f3 S# _) ?6 z
. G1 _7 ?7 @- P1 j) ^, k

' h8 ]* [! o) x6 D/ D# 在请求头中带上User-Agent,模拟浏览器发送请求7 w1 R0 e5 v4 P# |; h" U
response = requests.get(url, headers=headers)
) T" i7 M. x  j' J0 A+ {0 l* ^
* @! h2 K# {+ X% ]
  o9 ?& M& P6 g6 N& D, b8 h
print(response.content)5 g' x6 Z; A* W/ L+ B, \( U7 v

4 m3 Y  F8 h$ L: A5 C5 c1 u" m
$ Z: J5 l; ~- p9 z( P1 ?- L8 `5 z
# 打印请求头信息
5 i+ n8 ~9 H5 |9 @print(response.request.headers)
5 y9 a; f) K1 e' M9 I# e) ?1
' m% ~$ X& l6 [/ s" `2
& u& M; U6 Z- _- L9 W3
5 n( ^0 d( X+ ~8 q# }9 h2 @4
5 D; m# C2 X6 W  q! N5
. S5 k* J0 K2 P6
$ m8 i" Y9 q0 W$ X* l7- i# I3 Z8 ]5 `
8
$ d% O/ M) X  G1 ?+ M9 W( ~# Z% w9
' R- e, P! x2 C6 V1 d9 u4 s108 V3 {: I+ q$ P  m( l
11
% c4 M3 D3 K8 u' S- z" k124 h3 G3 Y0 `& C5 t
13
& Q7 R, S% ?/ I0 ~/ O' J发送带参数的请求
% Z. y4 f: X& b1 q我们在使用百度搜索的时候经常发现url地址中会有一个 ?,那么该问号后边的就是请求参数,又叫做查询字符串6 i$ w: [1 A1 u

+ {1 Z% l! a1 v$ k; N7 u; E

2 [+ V9 U3 a; J# W* u( c$ u在url携带参数,直接对含有参数的url发起请求
0 G1 J' f4 `, I1 l9 t, `7 ^! Y' H" }  u

) n! j* r' E6 ~+ {import requests
: y+ U/ x+ {" m3 ?, z* g( G3 p" A0 ^3 d
0 U* p) q$ ?1 C3 y) D5 X' ^
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}
1 W1 l6 P" p& W; Q* M2 X% c: R, i5 V; B6 ~# f/ N& K% I+ f

! z3 h, G  F1 X" u1 Lurl = 'https://www.baidu.com/s?wd=python'
* V* f3 R( C# J/ v3 Z. ~0 p' W) D. B" {, ]2 r* t

8 E, U+ S. u& P) s: O) Tresponse = requests.get(url, headers=headers)$ Q, a, o- W- K  q3 [* i

3 ]4 A5 b. s4 t6 I2 N

6 G: M9 a6 L9 g# S9 c6 z1
3 L& g! P( q& Z4 Y2
7 C3 Z- M" h" l! U8 B% b3
5 `0 X, T. }: d4
8 v- ]0 E" p0 O1 M8 F: j8 T5
7 ~5 X* E6 e% `/ V6
0 {, _. `2 ~1 [7 `2 U+ C) e7: ^3 |+ e' n8 A) ^# Y
8
2 r! B) y( m2 e- E' u* _4 q; @6 b通过params携带参数字典1 K3 l/ [+ L* i4 a# w

, @, Z7 E6 `) \+ C
8 F% x6 P7 L8 _: z+ c0 {$ b" H
​ 1.构建请求参数字典
3 b5 x% ?" ~# R% Q1 y8 H2 T2 [0 ]; f  d" x7 F- u
7 z9 {! j4 q3 B9 @5 G6 f
​ 2.向接口发送请求的时候带上参数字典,参数字典设置给params8 ?( q& ?4 Q' a3 I8 v, C
1 j& ~: k& X- W# {
) M0 @2 P. b2 v' d# j+ y
import requests$ J  m9 @' F& ^
) ]7 I4 _2 f7 G

, }+ w( C. U  W" iheaders = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}
( v' V" G: C3 P- H3 `2 j3 S# s7 r9 y: ~# B) v7 `
$ }* f% G% P2 T* W2 R. L3 L
# 这是目标url% n9 h  [  k, i1 n# Z" y, e4 x
# url = 'https://www.baidu.com/s?wd=python'
& `/ p7 |; G( e8 U, K
: y' r- |9 R# T% n; M

. C4 w0 f) ~7 C' |5 A8 }# 最后有没有问号结果都一样
+ P) q. H2 O% @3 lurl = 'https://www.baidu.com/s?'- ]! K' ]" @1 R& @0 O  D

1 S; o% h4 u( g/ ?( N; t, @' ?

& M: X) p7 M2 B8 K- \# 请求参数是一个字典 即wd=python: I) b! t9 ^6 Y4 _
kw = {'wd': 'python'}
1 w4 i# s0 ~7 B
& H+ Z* C2 b$ ?; m% u

" _$ w1 H: h' S# 带上请求参数发起请求,获取响应% k6 n+ c1 V4 ]. y- D
response = requests.get(url, headers=headers, params=kw), O1 q$ d$ h1 N

- ~/ _& l+ r1 b) ]" s

4 ]9 E6 s7 B" Zprint(response.content)
) J" w3 I7 M* q, F8 t1" `+ C+ L& L/ q# d6 p. E
2
- A# A, u( ?: M; [% t3
2 f# I! W0 ~- c3 D1 v5 g44 W, r& Q6 n9 B$ x' @6 X
5
( S1 X! o! u( C. ~% s8 A; }6
- u! h& z/ F, I: X7  a3 X' Z# R% o
8, |- _% I! s6 h% }/ y
9
) I7 s. i& T! V( Q+ r4 [( l* |/ D  l108 c* j7 x6 `2 d, y6 O) o/ @
110 j* [+ T1 E: k1 |
12
" Z" k* e! }6 U& v13' F# @# D4 t  h$ u1 w
14
6 m  H1 V' T7 _158 v) {  g+ T2 n0 u3 t, t
16% ~& k9 E3 f  t
174 \6 L* r) e$ }
从浏览器中复制User-Agent和Cookie
; p6 g1 ~; n. L2 H& e浏览器中的请求头字段和值与headers参数中必须一致) ?4 P( A8 J$ Z# F1 t! V
headers请求参数字典中的Cookie键对应的值是字符串3 [2 i- c) Y+ z
import requests$ ]6 ?6 c) C$ b* g' w& \7 w8 @

7 S$ \6 W! M: K. @5 ^2 N# z" s9 E

/ @+ y5 m  H/ c! A  I: G3 T) b6 Zurl = 'https://github.com/USER_NAME'
/ e3 K5 T  V5 N( H. ]8 V) m, b' _, n; b$ [
. f+ }6 Q3 c7 `: @" X) Q3 m
# 构造请求头字典
  h& @7 b* q& q/ Lheaders = {7 Q* w; b6 u& j. o% y. c  K7 T6 i$ j: f
    # 从浏览器中复制过来的User-Agent3 Z# D$ f' i) H4 V& ^
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36',
6 m; @% [; p* u    # 从浏览器中复制过来的Cookie
1 \0 o3 h: L2 M% {2 ?; P    'Cookie': 'xxx这里是复制过来的cookie字符串'
( l3 M# a& r+ A8 E}- c, Y! M2 i, [& _# ]* D, g

& Q, O3 M# s% z3 f  K, \" s. u
0 Y2 P: p0 |- i0 a5 d+ C& _( s; `
# 请求头参数字典中携带cookie字符串2 U# \$ r6 l) O4 I
resp = requests.get(url, headers=headers)
+ q/ c6 J! b( n/ j+ w" i/ H; h0 ^" i5 c  }2 r$ }' T

$ ]( a# m3 K# m3 s* @" N- R5 xprint(resp.text)- E4 H4 s0 h/ k, U1 r
1" M; m. c/ k4 }( G9 B( ?: S6 q: I
2- E. ?8 w$ w  h/ J: h1 f
3
) l% j2 ^  I" ^, N  k# F5 \4* D- L5 V, M6 ~7 m
5/ v( ?: |* g, j+ C, M
6
. s$ ~5 M6 d1 H) Y: y" y( q+ i) _' [* G7
4 n% u( f, w* m9 w6 X& Z; l8+ l- ?- E& A! U6 e- v: ^7 j# S
9
) h+ c9 _* ~9 r+ \" s10, e1 c& l/ [  k& S. ]
11
5 ^/ W/ s2 ^; i. [12. ]1 v! S7 E: l8 ~
13
+ R. s5 U0 o: P; t2 `6 l' [14
4 j& A3 X. Q( _' [5 d15
& @, b) c" U+ V  T16
# d  [" V( Q( ~9 r5 r' b) r( b& p超时参数timeout的使用
0 ^; R7 U! }7 L9 R# s7 Q在平时网上冲浪的过程中,我们经常会遇到网络波动,这个时候,一个请求等了很久可能任然没有结果。
* S. N% L) R0 p; M( G( z8 }0 I5 c$ E6 @$ |# I8 u
1 `/ o: u: j, R- f6 m! E7 K* t
在爬虫中,一个请求很久没有结果,就会让整个项目的效率变得非常低,这个时候我们就需要对请求进行强制要求,让他必须在特定的时间内返回结果,否则就报错。
1 A1 E7 _7 U1 K4 e0 p# n# _' p
, W7 G0 d9 }1 D' J& ]% A6 V) C/ o

6 y1 ~7 b, w2 \5 J& J0 Z% q超时参数timeout的使用方法& U# A1 L7 [0 y& s; d

! B" _# T% }3 s) `# n- e

/ K5 }, R2 \- P1 i7 C/ r/ z' Mresponse = requests.get(url, timeout=3)* k3 o5 [/ k% _. C% A2 y! M
# ]9 q: O2 d* f( g8 Z

& y$ }) ?( l. n# L1 y( v2 ltimeout=3表示:发送请求后,3秒钟内返回响应,否则就抛出异常+ V0 [8 u. b* s2 N
( ~% Q4 Q9 y; V2 X( V

/ i* R: E( C1 w; {) _1 yimport requests# b3 |) w% U# a& X; L; P

8 D" m. D4 f) r/ u3 ^) u
2 R- F! W2 G( _; E' W
' f# m/ J3 Z+ O/ G, z9 a
' o9 Z5 @/ _! t7 \7 x$ g
url = 'https://twitter.com'
0 I7 o# p% |* F& b! ?response = requests.get(url, timeout=3)     # 设置超时时间
1 M# S4 g5 p# }
% m7 ?# b# ?* D4 A' ^: O
. B# Q0 |9 }6 E
1
. u& M0 @- A& `$ a2: ~  A) ~  e1 C2 [1 W
3
- m3 @5 f5 q# |, m9 }2 C- \+ U# }$ l4% o0 p/ R: L; ]6 F3 [
5
9 r+ Q# j; M  @3 [6" \) V9 S/ S1 ~6 h8 G; |3 W+ \  E; @7 d
requests发送post请求的方法
6 I% {5 D5 p% e2 W7 l( T, c, Eresponse = requests.post(url, data)
# t* c8 K- h( _, W$ J6 c6 E* T( C  K8 e$ m: i: P/ c

3 u( O$ P5 F8 H4 a9 W0 h& l8 q; s1 [  vdata参数接收一个字典% F0 K- w. H2 B& M
& c8 r7 n/ J; f; P0 @6 T

" {3 Q; h: l4 Krequests模块发送post请求函数的其它参数和发送get请求的参数完全一致
% g+ O/ z$ i# i# C8 C
) C; r( Z0 K8 M" j% s: K7 {' w0 U

2 P- t/ Y* X: ?BeautifulSoup
4 I# [$ T% Z2 B$ P) c) T3 }4 ?BeautifulSoup官方文档 https://beautifulsoup.readthedocs.io/zh_CN/v4.4.0/% Y7 F+ i9 d, Q7 L1 i. b' @

: d# F. p# S2 D4 m7 L
* Q1 R( O4 ~3 r6 z2 B9 F
Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间.5 \+ ^" j* Q/ \* t
( e& E! Y: k. J1 _' C! _4 L) c! s
' v' T: C- `# o, `& e
; ^2 ?$ I3 r7 ~7 S1 o+ B
; g9 S) y  d. D
! S# \: C3 X0 @& l6 J2 @

" t6 X$ Q& m7 W' q- w文章目录
! {/ r( k6 X3 C' A) ~requests
+ ]7 d" X' v. M9 u/ _requests基础5 L0 Q3 x! B! U7 f4 n, G' E! ]
requests模块发送get请求2 }. z1 G3 i; L/ `, |
response响应对象
$ S" h; b. a4 O6 f. mresponse.text 和response.content的区别8 R& A% p. E! A0 a9 f1 ]# J
解决中文乱码( R; a* g4 }: h* F
response响应对象的其它常用属性或方法3 G3 X/ c9 f& X2 q2 Q. N
requests实操( m7 E) g% a$ j! Z" m8 G8 U( |
requests模块发送请求( v+ q9 c+ L+ s! z
发送带参数的请求0 \  k% e0 ]5 s& o- \6 C
超时参数timeout的使用
4 d: I& v) T4 Lrequests发送post请求的方法
# M6 Q6 d* E3 m" f; O0 V) I& zBeautifulSoup
1 x7 ]; C" Y( X( F% D0 \" ^( i& }常见解释器的优缺点
, s, F* W- t! y$ B常用操作
+ T! r6 M. N8 r; @+ {7 x$ L. S几个简单的浏览结构化数据的方法: Z9 J( ~% y% I1 Q% w) K. L
从文档中找到所有的< a>标签的链接
$ H5 m3 N& I. [# |9 h  x在文档中获取所有的文字内容4 k5 r. Z1 y( T& Q
通过标签和属性获取
% n$ q% w8 u5 \3 Q9 X( w( N3 ]Name属性" L3 T( s$ A7 O4 M
多个属性
5 N3 y; B7 |6 J* w/ O5 t4 ^# I0 x* m多值属性1 D) r! t5 i5 v
可以遍历的字符串
! G# m( o9 ]4 y注释及特殊字符串
  d: a9 f6 p. h9 u遍历文档树
8 X) r+ V( w. D' j子节点9 ?* j4 T$ Z! L' t# G/ \" p% B, y
find_all方法) e- {/ F: z1 r: A% e
.contents和.children
+ Y+ w- o( @6 U& H1 l8 |selenium
" x0 N% x8 o- r- Zselenium介绍
9 y" D1 l3 Q2 f# K6 V6 j1 xchrome浏览器的运行效果
6 X6 {( E8 `( J$ p& c: uphantomjs无界面浏览器的运行效果
. x0 F: {# ]% n! i+ B" Xselenium的作用和工作原理
2 \; T6 d$ w1 Vselenium的安装以及简单使用6 k# e3 P% c  F8 c% m' s% z
selenium的简单使用
- l8 }; ]7 j9 L5 ^lxml
$ K/ K' ?6 x/ \4 N: k常见解释器的优缺点
* r" u: J) I1 f' u6 `6 G1 X3 m
8 d4 b) F! g- v
  `$ K* r8 y# G

1 k$ u; \6 S9 p. \5 X+ g7 d, a

- h, p4 C4 H( N3 _( Q1 ]* B常用操作
9 @; j4 e/ U5 a2 `" S9 I安装方法$ F8 J- \- [* U! u- L
/ F4 h9 k" F0 B1 k7 j" D

7 {, p. |, s( \$ g$ mpip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple beautifulsoup4  + H9 T  \+ k6 F% S3 K
1
, C! C1 V& B' m' V6 f' h- l. a导入即可* G; Q) c* q5 |& r

' D3 F: w; x; R$ h) d
: e' S; y9 m& e. D/ b6 n& l3 _0 ?5 J
from bs4 import BeautifulSoup' W4 L: J: z) D; @% r
1
; W; b! ~  x- A0 B0 `html_doc = """
2 A& u& n8 D) ^( e<html><head><title>The Dormouse's story</title></head>
5 Y4 w' B# t) d1 w8 ]% N9 J$ t" T<body>0 W* R* F5 K- |$ h. {
<p class="title"><b>The Dormouse's story</b></p>
; v8 @# k3 |( E8 T* `  m6 U1 F
% a: ^, c1 A" ]5 K( |$ A

; w& R9 i+ D) r: V4 r<p class="story">Once upon a time there were three little sisters; and their names were4 P( N4 N) N" K/ x. @
<a  class="sister" id="link1">Elsie</a>,
, F4 k! [4 I/ r- U; f. j# h' K<a  class="sister" id="link2">Lacie</a> and
" S  D1 Q5 ~; j! }9 A! @, U/ q<a  class="sister" id="link3">Tillie</a>;2 L1 e  z& H& _5 e5 k4 O
and they lived at the bottom of a well.</p>1 Q$ f4 i* F7 Q  r

9 j' \+ k  p% D' H* m$ i3 h

) w% X! _! j! r; o<p class="story">...</p>6 P0 h3 {) [, ?. L5 ?5 S* z' b  x
"""
, B& m* }. c7 t6 a) X1" `0 [; }0 Y: g7 L# y6 M; e5 m' I
2
9 K1 T8 |" r8 m% a  J: J3  k# ]5 p6 m9 s# M6 B) ^
4
) `9 M9 N  M7 F, }# @- }5
; J/ Y& v" E8 M) z6
$ q2 C# B' _  H3 [; E) ]  y# m7
& D  h& O1 w4 B9 }8
2 f5 x) Y3 f" F* s9" ?. G% U7 V# }, [# y
10
+ Q9 x! O) ^! m* ^3 {# Y11" q$ H) N# V4 n6 D( y0 x
12
3 u6 P9 W$ w) f/ ~13
& P; ]2 O; @7 L9 t8 t0 Bsoup = BeautifulSoup(html_doc,"lxml"). @3 t: I- q* `/ ?
1
. i5 n7 m  N' x5 y几个简单的浏览结构化数据的方法
! j& P! h4 b6 O# R% O3 ?3 Q- ssoup.title
5 \! ]' y. }. v* j& R19 c( H# o6 C7 {3 G' y8 `. C
<title>The Dormouse's story</title>
  M/ N3 ]4 h( u* [; M17 _8 @( y0 n7 ^* R  F# Y
soup.title.name
# R5 P' Y6 z" q' _! L1
: U  b5 }1 U$ G: U7 p+ s& L/ b'title'
8 x4 i2 n' h% o, ~3 p9 w1  s/ X) S: @+ q) l7 ~& U
soup.title.string
$ C: Y& f6 G8 M; M; \6 J7 g1
: T8 x  s/ S7 k" t$ J"The Dormouse's story"
' C" g; N* d( n$ R0 B; d1
  t# M4 N% I  c& ?3 usoup.title.text, _, v" c6 p* [+ s
1
2 S" i5 y% D8 F' B# T% R"The Dormouse's story". L5 K- j& {. n9 h: k" A
1
2 ^/ d  l4 r/ Q- U4 A& D! \soup.title.parent.name
4 B. u9 @# h" j" b1, \' I# Y: p+ p
'head'
% ^! ?& E5 c/ R: ]% s' N1
6 [, {- l" x- A/ N1 Ksoup.p
5 i& C  n  S2 M$ `1
5 ^+ h( S) H% y' G( f8 u6 D2 p4 s<p class="title"><b>The Dormouse's story</b></p>
& g) _9 d0 X2 Z9 b1
/ M) ^: A7 S  O" @! }/ E" {soup.p.name
6 C: w: D4 W% B2 D) _' V* t6 n1
/ t& V% Z8 p% j; s, D4 T) m" G'p'
' A8 q$ Q5 Y& s' M/ r4 |1) z8 o: M$ E" s0 I0 O0 f
soup.p["class"]$ {6 @2 `- s' d6 _* N' g$ f
1& I( R$ j8 M% i
['title']
* L3 l/ Q/ M, v, E, G+ h8 x/ n1
# u: X0 C( J: Bsoup.a& `- l* y3 ~+ b# b% W% l
1
5 b* B5 L/ o6 S" {<a class="sister"  id="link1">Elsie</a>
- G- |+ k2 l( l1 L' y! q2 T17 Z& x5 ]( Z# G- u1 o; S) r  M  |9 ]
soup.find("a")# n; C, F1 t& L9 `: e5 Q) U" r6 t3 N# h
16 S! a3 A. g7 [, Q
<a class="sister"  id="link1">Elsie</a>
/ d8 g* d+ g& ?0 X$ G1
% q5 q4 e2 l( msoup.find_all("a")! p, [: k2 x% N& W* Z5 Y( f! b  H1 n
1# U0 i2 o) ]2 @' f, U0 d2 k
[<a class="sister"  id="link1">Elsie</a>,
0 [" |' `7 T* d$ R! h. h <a class="sister"  id="link2">Lacie</a>,  R& u% {; F" P. [( T& \5 K
<a class="sister"  id="link3">Tillie</a>]8 l& \# j' {$ ?  q9 X6 z1 ]" I
1
4 P) }; m) j+ s3 n7 O2
! r' a! z" l, _& k' W4 I3
, ?3 Z6 x8 `# R/ B6 s/ d0 Z( V从文档中找到所有的< a>标签的链接# ?0 W. `* H/ R0 u
for link in soup.find_all("a"):# O+ q4 G. p$ r, S/ Q
    print(link.get("href"))) }7 c7 \; M& C; `$ b( E
1) z5 u5 R9 n! f! |+ w, A
2
' }+ Z$ f- }! T5 Dhttp://example.com/elsie  B8 J" r7 `, y+ v' ]5 G2 {
http://example.com/lacie
# K' ~: x, l0 q$ V/ T. Lhttp://example.com/tillie/ c1 O' |% A8 {
1
2 M5 U9 m6 ~" l; S% v% ?27 i: j9 \* `5 i6 j! P4 y( m8 S
3. l; H, d1 {! g% M( [) o7 A& H
在文档中获取所有的文字内容9 H6 n" n& }7 n) u
print(soup.get_text())
: N2 I  A4 `" @5 K1- {7 R( v) ~/ o
The Dormouse's story
- {5 |* }( Z, H# y! U# ^
6 k. l- b4 Y  D1 y
) e4 Q3 Q; V' W2 A, V. Z. D* u) [1 ~
The Dormouse's story
4 h& u3 s' Z, ZOnce upon a time there were three little sisters; and their names were5 O3 ^% v5 v- b* ]3 D7 m  I) R
Elsie,
$ t5 y/ [8 t- S- W- M/ Y" aLacie and
4 L0 }; \6 L% q0 STillie;
' f6 }# Q( T/ c1 @' u2 Yand they lived at the bottom of a well.
- w" P( T. M- Q7 r1 f+ O...
* @+ l$ w  G$ d1' Y+ R3 V2 j. W8 m, `
2
+ g1 ?6 G  V: D) f3* U9 \5 F+ w. i# d# P
4
# r/ P$ ?$ {) |8 n" b59 w! k* s' i" e3 l; b, `5 H
6
- r7 l& t7 j( M  [; m) n1 S7
( K0 r+ _8 {: d. G+ F; L8
4 N# ~. u/ l* V9
. a, I; j0 z, Y) U% A- E9 r; E5 b; U# P9 h6 S" W1 L+ }

6 n& }& e& Z5 n
) T) H2 q+ o6 Q4 }5 ]: t9 U
通过标签和属性获取
9 J5 h; N# a$ Q: w( j8 F. UTag有很多方法和属性,在 遍历文档树 和 搜索文档树 中有详细解释.现在介绍一下tag中最重要的属性: name和attributes& ?* O( q& o# P5 ?+ b" ?; z$ t1 p
soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')+ b( d% Z' y! ~/ m* v" h8 H
tag  = soup.b: m. h1 O; H. ~6 i4 u8 X5 y
tag
7 i2 |  }( ]- {8 ]& `) Y; c8 h1
- s$ J" a: X% x6 Q# l2 L2) S) R9 h& X" r# T& c5 M' c
3
8 C) J/ j) i$ G- J<b class="boldest">Extremely bold</b>. y! r% W; s1 x. R& r
1$ Q$ j( h% Z5 n& I
type(tag)3 D( r; J7 b9 `/ V' W
1
9 s) R3 S& x* x8 u' Mbs4.element.Tag# m; n4 n2 K6 l
12 l' Z5 q6 {5 E+ H" [
Name属性
  l7 L' C: u: j* I5 h每个tag都有自己的名字,通过 .name 来获取:# R( \5 X$ c  W6 J9 o# F; D0 X& H
tag.name! Z! u; y0 s+ u
12 ~' y) `! S+ m" h' a* K+ W6 ]$ F& S
'b'& C3 y% n: {+ T" O. k
1
. R9 H) ]1 b- y如果改变了tag的name,那将影响所有通过当前Beautiful Soup对象生成的HTML文档1 P' S* l( ^! c+ D# m0 ~
tag.name = "blockquote"
0 O0 q5 T7 @" X% _  V+ F. H, Ptag& u" M! U( _+ L0 r6 I; v5 c. O
1/ V3 d) P5 N" m* u% `6 A5 \3 A, B
2
* E; f& G4 Z/ P6 |. J' R3 I  k& v5 O<blockquote class="boldest">Extremely bold</blockquote>
( i8 Q& y3 C" A* X4 N( Z. E1
# @! C: r6 P& Z! x2 o多个属性$ q3 X8 Q& o+ v
一个tag可能有很多个属性.tag 有一个 “class” 的属性,值为 “boldest” . tag的属性的操作方法与字典相同:
2 `1 O8 q3 y+ v. J. Atag["class"]
, P9 I- r3 a1 w9 i9 p10 V4 d' U4 D9 U+ S( F
['boldest']
- r* d1 l* c- O/ I* _1
6 b, ]; O: {& ?; Ptag.attrs
) L4 ~* f3 t4 Q7 S* T$ i1- t$ H$ l) S: `% t4 r/ k
{'class': ['boldest']}/ D8 ~- s! e, |! |" N: I
1
3 d8 }  D+ H! Q) ^" R3 T5 [tag的属性可以被添加,删除或修改. 再说一次, tag的属性操作方法与字典一样6 u. I9 [" ~* z2 T3 x( @
tag["class"] = "verybold"
6 F6 h) f1 I1 _tag["id"] = 1
4 t5 x6 D2 w1 }: ?- U/ [tag
- N! Z' S$ h! J* L$ E& e* C1" Q' M3 F/ w  Y0 h  b3 c
2
$ \* v( n$ p( Y3
9 Q5 X9 R6 h5 U. r+ f" I% H<blockquote class="verybold" id="1">Extremely bold</blockquote>
  ~; a: {+ I# w/ n1
" e' n( }$ o6 a) H0 x# u0 F5 v9 jdel tag["class"]
4 E2 ]: z$ l6 P: Atag( X; `& ~- K6 `0 }
1( P7 S$ E# U! V  h* _
28 T- I4 p( n* I
<blockquote id="1">Extremely bold</blockquote>
6 }, U4 m/ Y  V* a1
8 \' V' S8 N' ?& D6 v0 p多值属性
: R, J! ~! d# B9 Y$ Ecss_soup = BeautifulSoup('<p class="body strikeout"></p>')& @; K! A; m6 N" z+ ~" \6 J
css_soup.p['class']: f% m  Q$ F9 w( p9 D9 ^
1$ v. s& X$ W' r5 O
22 S, t3 t" a% m6 a7 k
['body', 'strikeout']
4 i! I0 X- s3 L7 g4 R4 l2 F1$ U' L( p0 o5 f2 X/ G/ K# t9 k9 S
css_soup = BeautifulSoup('<p class="body"></p>')# R1 }4 q5 Z$ `' ?0 G9 {
css_soup.p['class']
/ D( O% l# R) _9 t3 M11 `) b1 h3 Z$ ^& p6 U  n
2
* j2 L' k& _* V4 u4 {2 k+ D['body']
/ k* ]" l( d( f. ^3 {$ Q8 q: q1
/ G8 x3 k4 j4 q4 a8 p可以遍历的字符串8 ?( A( q3 }  T. M1 K! e0 j1 i
字符串常被包含在tag内.Beautiful Soup用 NavigableString 类来包装tag中的字符串:3 @5 u; `" u0 z# I  T+ V
tag.string8 `. {+ }+ ?3 Q1 U
17 [! n$ P; e/ X+ q8 _* g4 o, V1 G' {4 J
'Extremely bold'
5 t  w( }+ d3 p/ M3 ]: A$ y+ y: A  e1
  ^6 Z2 c" Z8 J, v& q; G: x2 e1 @type(tag.string)+ u' |, p1 r5 ]$ d
1
* F' F' y: }; [4 b; G4 nbs4.element.NavigableString" b5 ?7 W! @6 Z2 N- n
1! g2 Q4 C0 o! F: {6 O0 |0 |
一个 NavigableString 字符串与Python中的Unicode字符串相同,
" E8 e7 c8 |, g$ M$ O; r% K: U0 ^并且还支持包含在遍历文档树 和 搜索文档树 中的一些特性.
* h5 n! f: F# j# V' x通过 unicode() 方法可以直接将 NavigableString 对象转换成Unicode字符串:6 n. }. ~! K5 c- ^8 L
* S- N7 b. ]4 I$ H- @

, l2 q# _; u# O& h. C- a! Z1 atag中包含的字符串不能编辑,但是可以被替换成其他的字符串,用replace_with()方法
4 G. c& h( {! f+ ]2 h
' {2 v" R: v* j8 C
. _* p) M+ j# T! p
tag.string.replace_with("No longer bold")" z- m( t. \' Y; _
tag
/ j# H/ E+ q% G. X- U: j17 T- h/ k- ?8 C
2
" e) T/ S1 ^% ~/ W9 r- _/ Q' o0 M<blockquote id="1">No longer bold</blockquote>
4 C3 D5 e% g8 [1 `0 Z" y5 [& h2 u1# g( j, D7 f1 F! |! F: z4 T
注释及特殊字符串
7 b! X2 ?+ T6 V: G文档的注释部分
- \" Z" p: G- n0 W( |. k) H7 Imarkup = "<b><!--Hey, buddy. Want to buy a used parser?--></b>"  O6 k& E) [7 B) @6 T
soup = BeautifulSoup(markup)6 y9 L2 Q, ^8 P' g* b( B
comment = soup.b.string2 o- c0 E6 b& m% s5 `6 C% O
comment0 Q8 O% @9 y, c0 |1 m4 N% [2 t
1
. T; M- N' S. ^+ M: U% d! I8 }& M7 s9 R2
4 Z5 Y. |" b( f- J3
+ S4 i% S1 \, u& @41 R% h' \9 ?8 g  K: S  R7 c
'Hey, buddy. Want to buy a used parser?'
* b2 z& J- t) Y4 e12 G  s1 D- [# M; s
type(comment)
. h3 s1 T/ N. v. Y( N2 \1" c6 q0 X/ K/ I# e4 B5 t% p: r( j
bs4.element.Comment# E$ r- b, \! Y4 f5 D: N' Z' C% I$ G
14 f2 j* H, Z9 O' c3 w
Comment 对象是一个特殊类型的 NavigableString 对象:: q) j2 |4 |9 \7 S' s& r! C
comment
+ M! X0 g. P1 M, ~3 r15 H/ d" r' d" r' U5 h  z/ q* G+ ~: [
'Hey, buddy. Want to buy a used parser?'8 v9 E+ G, j, f1 ~3 V; \
1& X6 B+ t2 h. N' u. Z5 }- ?
但是当它出现在HTML文档中时, Comment 对象会使用特殊的格式输出:1 `+ _& I7 X/ f2 X" G

2 a+ d+ S9 r1 @) p1 Q$ Y& Y

/ R0 g/ |7 u, `: dprint(soup.prettify())
3 n# p$ h  u5 O( z1
' g5 D, L3 v- H4 D- m7 d7 c<html>" u2 P2 ~4 N1 W. y' I- B& _
<body>. y! ~& d  ?% `; e: a6 e
  <b>
- e+ G/ V  v# K& x2 C1 i6 V5 J1 l   <!--Hey, buddy. Want to buy a used parser?-->) X) e5 F! D1 ^; h' C! s8 E
  </b>
: `1 A" u& ^5 o3 P </body>
* x; r% E6 |% K# F% h( H</html>; |- i9 Y& Z3 A' k2 d7 L9 Y; e
1
0 Z8 u# G5 O8 F9 c. B2) {- c3 \! G: |9 |5 n. L
3
* \( R3 b2 Q% U; i' m& M4
1 k4 H+ M. i; A$ d  s2 b/ Q5
1 M9 ^6 P: F/ P# f; y6
  I! w' ^  S: H+ _. E7
0 p0 D! _! n- Xfrom bs4 import CData2 g+ a7 F& v  p" E7 H4 H  t
cdata = CData("A CDATA block")
8 K: A  b/ U# |. j  pcomment.replace_with(cdata)# R9 |/ i4 m( g- ^# X( w
print(soup.b.prettify())' {- w6 S3 t# u; N3 l( p2 m
1
1 Z9 C) b6 m: C- q2' o" D( i) Q" |( Y. F% T0 t
3" F! U1 k  S# z9 Z; e
45 ?6 n) n, T" j+ m
<b>
/ Q8 Y) D" L/ R4 h <![CDATA[A CDATA block]]>  s# f1 v8 Y$ }
</b>
( h( j3 v3 e6 S1* D# ~) W6 {3 G) f4 K: O% a# A
2* N% Z8 u2 Q  f8 z
3
3 `6 i9 M9 k, s0 y9 Y3 d遍历文档树
3 w/ i6 `5 y: _  t; O2 k' V* V4 shtml_doc = """( ?* c. N+ O6 @' i( X& F& ]
<html><head><title>The Dormouse's story</title></head>
" O# a3 \1 A; [; s. |    <body>
" j% X5 O. a1 G+ |9 B( _+ L<p class="title"><b>The Dormouse's story</b></p>) [: H3 J) r# G8 \+ f8 H' p

- u! I- T# F7 c9 Z7 [

+ |4 m3 j3 k; H* `<p class="story">Once upon a time there were three little sisters; and their names were7 k' h+ L: `. [8 ^; \: w' V
<a  class="sister" id="link1">Elsie</a>,
0 @: V1 p2 R% v  q<a  class="sister" id="link2">Lacie</a> and$ J# n1 i+ l* G8 ~) }
<a  class="sister" id="link3">Tillie</a>;
2 s. K: B' v! Mand they lived at the bottom of a well.</p>4 G, e) c; }$ S# ?! G

3 @# |9 a) a- i, A
+ a3 E4 B  u* j$ n( ^3 C8 X
<p class="story">...</p>
6 z6 l1 V% ]: U"""
9 G( D# W5 }4 @/ T. W1
: i4 r6 ^) r- A$ ~& J" l4 C4 l2
& z. H& l' ?6 d9 U' a5 w3
/ \/ ~8 j- K) P) |! b: p0 D0 G9 e4; v" L; n+ Q  Y: k* E+ y  k( l+ t
5* o6 ?' e: Y  N. F# y1 h5 O: V
6
4 Y! u& z, E; B7
9 s% Q0 u0 {5 x* M4 r  E8
! ^$ ^2 i8 c. D# O9# Y2 l8 z8 K1 u/ h6 a
10
0 ?+ |! \" c2 i9 Q$ x; Z8 \8 U( Z113 m2 m0 z7 t1 d0 e7 V
12
' C" N9 ?7 {, F9 V9 r) u( T13
# e6 X/ Q" ~1 L: `+ Z2 z) N  Vfrom bs4 import BeautifulSoup
# G4 w6 ?3 @. T" `1# d, v0 [$ P) j# c9 m
soup = BeautifulSoup(html_doc,"html.parser")
/ e# o3 |) n# X* K2 \1
' u4 F! `0 C/ [8 }* V子节点9 ~3 g& c" ]( t: h7 P
一个Tag可能包含多个字符串或其它的Tag,这些都是这个Tag的子节点.Beautiful Soup提供了许多操作和遍历子节点的属性.  H1 L2 _  m3 ^, W: |8 j# k
( V( b- F0 Z" j/ J2 |8 g0 U3 v$ ^: H
( u* W+ G" e  d6 o, F
soup.head5 [% M9 @: h, Z7 H
1
) |0 Z, c% n0 t: F9 \; ?4 R<head><title>The Dormouse's story</title></head>8 Q1 r0 w  x% E+ Q# M, _
1# \! L" B8 y( Z# ?1 b
soup.title
) }! H6 g3 s" N5 b7 F6 J/ w; i15 {* d, I* U9 R  Z
<title>The Dormouse's story</title>
1 j* @( ^4 D8 ]6 Z" G& t6 m  u1! c5 q$ w+ H0 |
这是个获取tag的小窍门,可以在文档树的tag中多次调用这个方法.下面的代码可以获取标签中的第一个标签:$ K0 J5 O" ^+ B; K2 ~6 G" v/ I) e% Q

9 D# h2 U8 Q: }$ ~* c3 g0 V, }& X

" [' \6 Q9 n/ f( b. \- W' ~soup.body.b
& c4 ?, U" M! q& v2 h% n13 n7 v& E9 M6 {2 q
<b>The Dormouse's story</b>
/ Q! k1 T- B" T/ I6 v1
; b1 k& L4 N- p9 ?( G. Z+ v通过点取属性的方式只能获得当前名字的第一个tag:
' x, a5 `! y3 C2 K: V
5 b& O; e4 S2 }$ o- u- T7 q* r6 ~

& C7 t) t0 z- x3 A) Isoup.a
& p+ ?7 `" c! B10 s: z5 X8 t8 j( n/ R
<a class="sister"  id="link1">Elsie</a>0 g! Z( F2 M- {8 v& I$ f4 f
16 q  a" b* h- P2 q$ G- `
find_all方法
0 j6 x7 z1 J9 s0 b0 O$ C, l如果想要得到所有的标签,或是通过名字得到比一个tag更多的内容的时候,就需要用到 Searching the tree 中描述的方法,比如: find_all()  K' J  Z* e6 C# i* {

0 i- A8 ?1 \4 z" m' {. [

9 q/ [  O' ?9 N+ t) U, u/ Hsoup.find_all("a")
1 c! `4 \2 K$ d) r3 a( f& o) z. x19 r8 ~7 d& ^( r6 ^3 K( Y- `$ O1 C! b
[<a class="sister"  id="link1">Elsie</a>,
7 {" n7 y. G6 Z& Q: s <a class="sister"  id="link2">Lacie</a>,9 a! s% X6 p0 H$ @* n$ s- s- c! B1 j
<a class="sister"  id="link3">Tillie</a>]! ?, E8 l$ L' v+ c0 Z5 n! y6 @6 A$ k
1
8 N; w: I, W9 i4 K; y5 {1 }2! P3 o7 W1 Z9 x- V5 a$ m' k
37 U9 W1 G9 p  [! t/ D
.contents和.children
5 `0 w# l5 b0 a9 X0 Fhead_tag = soup.head
: [& Z" F. ]8 x7 `2 D% }5 Z0 C: vhead_tag! V+ J4 U  i! ]( Z1 L
1
3 A- L  z' J! X* U* S2 i2
! ~* f) z1 y$ w# b<head><title>The Dormouse's story</title></head>
2 |% M( j5 R* S  [  Z. j1
4 s, u) s4 C5 hhead_tag.contents
3 \: h; S) Q6 y/ f8 R5 ]- d10 `5 E! U# U) w
[<title>The Dormouse's story</title>]' F, e  t, D" X# {$ `0 `
1
  E3 K9 d4 i9 @8 Rhead_tag.contents[0]* S# {" u. f- O- m
1
9 b" M# A% _$ c<title>The Dormouse's story</title>) q8 {  W9 N7 d8 h! h, ^( z4 M
18 C1 A  R% j- O' O$ A- V3 M" F
head_tag.contents[0].contents) P" ?. \: }( f0 }- T% m" @# H
1
3 _; j: J1 m' r["The Dormouse's story"]2 y1 J, F, M1 v, a4 ]6 X
1
( l( z! \; K7 Rselenium
% i" U, x" E( g1 k' ^9 z" w, F/ k$ z1 e

. s% W: }5 o$ o1 b% |- h
3 B6 M5 }% L3 s/ _  M* o; |) ?

4 d) {  H1 v! e! G  rselenium官方文档 https://www.selenium.dev/selenium/docs/api/py/api.html7 A8 J9 ^1 O+ c: s* K. ]
! T9 \3 K+ P; o

7 L7 U  _/ z$ k( Eselenium介绍$ h6 w, H9 m4 O% J; @. `, C/ k
chrome浏览器的运行效果
; C& A( \5 `* Z0 H6 ^( l在下载好chromedriver以及安装好selenium模块后,执行下列代码并观察运行的过程
, h. d" m# X$ O8 [$ {& n' D3 f3 d3 M9 \

; |5 d9 e7 W8 L$ {+ P1 Tfrom selenium import webdriver ! g& ~6 w* f" r, E

* U3 S5 X/ r2 W4 K# t8 @! z/ K8 }
$ g) Q, s7 @" l, |
# 如果driver没有添加到了环境变量,则需要将driver的绝对路径赋值给executable_path参数
" v$ r5 A4 m$ P; \4 f# driver = webdriver.Chrome(executable_path='/home/worker/Desktop/driver/chromedriver')
8 p9 O* G8 s) Z+ \3 E- \6 `
) @+ G" P7 V6 b  C3 h

$ k$ F" a2 X' E6 x# 如果driver添加了环境变量则不需要设置executable_path
- ]$ b& ~2 k, t/ A0 s# _driver = webdriver.Chrome()
* I8 j! d; P8 t8 B
! _# y: v+ K  K4 t/ A

2 K* r' {3 Q, \3 W# 向一个url发起请求
* h% _) l3 B  k' Ddriver.get("http://www.itcast.cn/")
5 }$ k' ]7 l8 N6 V7 w5 k  G" U! h! Y
5 o5 |" U% }" ]3 j- ~  I
# 把网页保存为图片,69版本以上的谷歌浏览器将无法使用截图功能
( E+ z2 r# ~, ?' q0 X" j# driver.save_screenshot("itcast.png")
4 ^' N  p* z3 A
9 m* u) m  \/ `: ]7 J6 W
. P6 [( M0 o+ Q; L* H
print(driver.title) # 打印页面的标题$ s/ _! ^$ K8 z. t7 y5 L' g# P

( d% F  g3 ?, r9 h2 k

# ~# y5 g4 w* W" T0 a& i4 X# 退出模拟浏览器
, c& `5 e) ^9 {! Y# gdriver.quit() # 一定要退出!不退出会有残留进程!
: |0 c. V# Z" @9 |: S1
3 U: g! g+ w4 t2 H0 T: D26 B& i8 M$ C: N8 ?! V: S, P! f
3
; c$ i; z" o  p5 N% O9 b4
' T8 ?9 |$ C3 B5 ?5
4 d; }& R# g5 D6 J/ Z9 W6+ d9 _# i4 ~2 a5 @+ a
75 k' q% r% l' L4 b& T" N; R1 f
8
$ i  ?: e$ }& v& A$ y9
4 Q4 i6 A; N) R7 O10
5 ?  s9 B+ |# H  j110 u% f5 d$ |" s1 K( u: `& K6 r
122 a& ~/ Q8 G' p* y( W
13' s8 J1 j- G$ K0 ^
140 j4 Z- N6 b! P
150 Q: }- ^, x9 E* b7 P9 e
16( S) ?, \9 C- v5 J4 a" ~% ]1 S/ b
17" ~" W# i, n# ?, x
182 s1 u8 k) O, t( o' \2 d! e" `' x& {
phantomjs无界面浏览器的运行效果1 |7 H! R+ W! j8 ~# J
PhantomJS 是一个基于Webkit的“无界面”(headless)浏览器,它会把网站加载到内存并执行页面上的 JavaScript。下载地址:http://phantomjs.org/download.html0 G5 o, |- ~. @0 ?( |
- E( K* k8 k: Z" A

2 E+ _! L# \+ B+ L( [! ^from selenium import webdriver / }# _* q2 h; r0 u1 S
% }1 f0 @8 _- x8 ~' `4 [: K
6 R* q& t% k' T
# 指定driver的绝对路径
+ R7 F6 z) v$ x/ Ldriver = webdriver.PhantomJS(executable_path='/home/worker/Desktop/driver/phantomjs') % i# u0 v! `4 N8 I; v  m
# driver = webdriver.Chrome(executable_path='/home/worker/Desktop/driver/chromedriver')2 X4 `& z1 ]5 v- x- B; x) _% S4 {* U
) |4 z; o* J6 q; ^# ]4 g

  I# d" R* Z4 M9 Y' @# 向一个url发起请求+ d4 i' `( E2 Z4 |* h
driver.get("http://www.itcast.cn/")& f8 Y% E, H) x, q7 v- Z/ r$ K+ H

, F+ m0 k( D8 \5 w9 w8 D

, S/ a8 b7 _2 A% R# 把网页保存为图片2 H$ G0 M* i2 ~# B
driver.save_screenshot("itcast.png")3 f7 N4 f% i" w6 s' B# d5 K: g, n

% u  k: I  y  R; U
6 B9 M) F0 I2 _3 A7 v; @2 k
# 退出模拟浏览器: |& j, `; i0 e) ]/ i4 n4 U. X
driver.quit() # 一定要退出!不退出会有残留进程!3 w" `+ Y  ]8 p8 I' g& z
16 h* S% Z; S; I) e$ W3 K
24 k9 {  t; t) _, w6 V. x: L
30 _" o$ S% R: w7 w' c% Z" N
46 D2 K* z$ ?1 ]" t9 t
5, D4 z/ x; E' L& K5 H- U
6" C: P4 [& k/ ?$ |! E7 a9 m
7
' n, U, J) z; s- v8 u% C8
; x8 Z: o# D3 [6 S5 N* P' e; w9
+ Z* f& h! J+ u# h10$ T8 S3 K+ Y/ b& l( I8 C
110 w* y& H8 G9 G
12
: D; C' [! {7 Q3 b& R13  s- h  ]( S2 _1 Y$ I( z+ m
14! p; v3 L# t, P
无头浏览器与有头浏览器的使用场景
% B/ C$ t2 ?1 D. P
/ q: c1 G$ w) I2 ~1 C3 f" _5 F6 ?

* g, L0 j6 D: v+ ~通常在开发过程中我们需要查看运行过程中的各种情况所以通常使用有头浏览器
# X/ E+ w3 `8 }- X  r0 G4 B在项目完成进行部署的时候,通常平台采用的系统都是服务器版的操作系统,服务器版的操作系统必须使用无头浏览器才能正常运行# Q7 O  H: ?* ?% I7 \9 d) S  M9 A
selenium的作用和工作原理
* |9 f6 x1 y- H. z4 k% P% i利用浏览器原生的API,封装成一套更加面向对象的Selenium WebDriver API,直接操作浏览器页面里的元素,甚至操作浏览器本身(截屏,窗口大小,启动,关闭,安装插件,配置证书之类的)- K. W- @! r/ }: E" g  @/ B8 V

2 \* R0 M3 ^7 m9 ^$ J

- H" Q- W* }) S% |7 W0 Z/ [; `selenium的安装以及简单使用# N  |% ]1 z# X6 U# N
以edge浏览器为例 参见这个blog哦,驱动chrome浏览器同理  E4 h: V$ k+ O8 T: c
selenium驱动edge浏览器+ K4 i8 l  P: A. V2 D' c4 m5 o8 i

6 T* X; f. ]' {) i- f4 N
; U  O: d! |0 @2 r5 Q2 ?
chromedriver环境的配置% h& E4 r) {4 Q$ w. v6 I- w- @
windows环境下需要将 chromedriver.exe 所在的目录设置为path环境变量中的路径
0 l7 t' l- W2 G* nlinux/mac环境下,将 chromedriver 所在的目录设置到系统的PATH环境值中
- m3 d) ?- I% }$ h8 U2 vselenium的简单使用
! f; k  f6 w7 n# N6 C+ G4 l6 u: s接下来我们就通过代码来模拟百度搜索, i7 K1 h8 Q& L$ X
. ^  y6 ~' M: _+ J7 W

7 y# E9 D0 z$ C) I& wimport time/ @& _- G* ^# g# G' ]
from selenium import webdriver
) z2 g" X  ?- T3 k" x5 }9 ]0 c. g  ?3 l* j& t% F- Q
7 O6 ^; k8 t. \
# 通过指定chromedriver的路径来实例化driver对象,chromedriver放在当前目录。! X- m( z; {; }: ]2 J4 t: \
# driver = webdriver.Chrome(executable_path='./chromedriver')
. q: Q, X9 F! M3 r6 k2 p# chromedriver已经添加环境变量; ~1 @2 X8 I5 G' E1 q1 V
driver = webdriver.Chrome(): f' P% n+ [! ^7 V. `% T
& f" F& L( p& s

! M) |* O) M9 \; ~, ~! h+ C# 控制浏览器访问url地址4 ^; v( }  O/ r' B) @
driver.get("https://www.baidu.com/")
" t) K% c" y  U
7 b6 R* X# p2 p* C0 m

4 ]* P6 C( Z( q0 u/ d# 在百度搜索框中搜索'python'3 @; R+ r0 M: A+ Z! g
driver.find_element_by_id('kw').send_keys('python')
6 o4 u: F) s. L8 R# 点击'百度搜索'1 |( @  r( t( i# e7 C% Z% l
driver.find_element_by_id('su').click()- q8 i  h7 C, S4 T6 Q$ h. k
& s+ h8 W& g% _
' n# e% I- x4 n6 E- T
time.sleep(6)8 X/ u- z6 s/ L. D3 J2 L
# 退出浏览器" d: j+ W% ~& Z) M/ ]6 Y
driver.quit()" l; x" E% }9 t
1
  w0 l! s+ E) S) W, I* d9 W/ U% m2
8 Q' J% q' P  L& k3: a$ A( }, G/ Q6 i
4  u: v0 |2 d) l. `9 h  G* O
50 u' T7 Y- h1 i4 l  _7 X
60 t2 }5 y5 A) D4 ?9 B
75 _* O* x8 s" y) c8 n" d
85 ]# J8 q: E# G3 k! a" G0 }% n
9
, `  q; X7 K- T- n9 c10
9 l* W9 i6 D( ?5 ?; m, C112 T7 }7 R# k9 `
12% A  P4 s: P% L' ^
13/ i3 g5 \0 h/ l
14
6 x4 W" z3 K% C. X5 C( A! Y9 p( G155 |5 D9 w; k8 C- m  g$ J8 O
16
9 n# n. S. [, w. ]' v179 a: r+ Y' [: W; G- j; f
18. m/ c$ W1 V$ a3 q* B
19
# g3 x( t8 ?; jwebdriver.Chrome(executable_path='./chromedriver')中executable参数指定的是下载好的chromedriver文件的路径8 }" z2 W0 B# K0 s( M# Q
driver.find_element_by_id('kw').send_keys('python')定位id属性值是’kw’的标签,并向其中输入字符串’python’( c! J+ m1 O' Q4 m5 i* A" }  j; g
driver.find_element_by_id('su').click()定位id属性值是su的标签,并点击
2 Q. y8 b/ F) Q& Lclick函数作用是:触发标签的js的click事件
. w  h# k7 \6 |& n. ~值是’kw’的标签,并向其中输入字符串’python’9 `! R- j( p5 G/ [, V* U) b3 ~1 j; r
* q- X4 w5 b- X

' \+ o% d7 h9 [0 ?7 f+ o. mdriver.find_element_by_id('su').click()定位id属性值是su的标签,并点击
" C6 \8 o; F4 S$ N) lclick函数作用是:触发标签的js的click事件* V  W* w' T8 G! b
使用xpath来提取数据,爬取数据的简单语法。
4 q; \5 o' t' x" }, d
% r* D4 G4 q  ^8 s& w

' n7 C3 y0 G- v, V1 R9 glxml
8 s7 \) C' o# p2 Z3 v
7 o9 y/ h: [1 \. }4 Z
, s/ b- O" P9 s1 Q* [  k6 O) M
+ r8 J* B( Y( Z3 e. b

/ i. n1 Z) |8 A% ~requests官方文档 https://lxml.de// R$ a) V; S% P
( D/ R) U6 T! N0 ]" ~3 x3 T& s& t
; a- Z5 O( G" x
pip install lxml
+ X4 s7 t1 @* @- C1
8 }  N# \1 |& L+ Z4 N9 f$ [1 Y导入模块
% o1 N, W- X7 o, h- ^; K& Ofrom lxml import etree! G; i. T( ^! p2 i5 Z0 l
1
$ L3 t( l. b* w! i利用xpath获取text或者href内容6 _$ G" v7 v" D* Y
/li/a/@href 这样取的应该是href的内容
* P& ]  T$ b8 O5 F! E+ q7 Q8 H$ l/li/a/text() 这样取得是text内容1 I! H/ x6 X' S" o0 F; Z
1
3 I8 x. _. |, i# @& }" u/ T25 s( ?' l, B/ I& j& b
etree的使用. m8 R" A$ t$ H) @) g7 {/ n
h=etree.HTML(response.text)#response.text是网页的源码
: F; _% P5 O1 H2 V# uh.xpath('//img')  #寻找所有的img结点,7 e- E2 p# z4 r8 {0 p2 Y
h.xpath('//div').xpath('.//img')#寻找所有div下的所有img结点* S( P: I0 i% m. o1 K6 z
18 S1 ~0 l7 D* I# L
2
- X: g% k# G7 D7 j# \/ z- A3
7 z3 K) C7 d" @6 S- G, @xpath的语法6 d/ w, e  g0 T! q; A# J
符号
) L! q. s7 V) t8 R  Y: ~6 ]: e2 gXPath 使用路径表达式在 XML 文档中选取节点。节点是通过沿着路径或者 step 来选取的。
; X5 V* u0 R' K) @5 @1 U1 x( p' W6 N7 @( R
+ m8 W3 o, c' H- G. u
表达式        描述
0 ]" V0 {5 d7 G4 z' R* D/        从根节点选取/ H0 X  a8 |1 ^2 C  v% E- S# V: V/ Z
//        从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
; ?9 ~$ @3 Q& {7 [( t4 c# M, X1 z& U/ s% H.        选取当前节点。. Y: ^1 V/ D7 Z: J6 m; i4 \
. .        选取当前节点的父节点。* e1 W9 o8 o/ N. T! d- S
@        选取属性。8 ~! V7 V" R& f" w
|        在两个中结点中选择
& m4 E" G) ?. p7 n* y()        用()来包含|
, x% U# ~( N# \( f, y*        包含所有元素2 D9 t% v  C% {2 \; \8 c3 Y1 R
not        取反: M( }; q5 u2 \( a/ e
实例
8 i' r! ^! l) F8 R( n% v- X
" |& F' F& N, |& U3 C0 f1 p
( n) c/ t2 [  z7 G" q3 c
路径表达式        结果
9 r7 ]6 F& V+ W$ c& V% Obookstore        选取 bookstore 元素的所有子节点。+ Y7 @" F" w% e9 M( b& W. D
/bookstore        选取根元素 bookstore。注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径!* Q! w0 U) [7 I# s& I
bookstore/book        选取属于 bookstore 的子元素的所有 book 元素。3 L- Q3 S) q5 R+ K
//book        选取所有 book 子元素,而不管它们在文档中的位置。& ]- q6 l: Q# d# Y+ d
bookstore//book        选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。9 ~1 X4 T+ P( I4 R
//@lang        选取名为 lang 的所有属性。
. J1 Y1 f1 X! g1 N1 Q//*[@class]        选取带有class属性的所有元素
' K% j8 J2 S3 y3 g$ R4 g: B//div[@*]        匹配任意属性的div元素. E: s/ m. p: U; y* X9 z1 Q% T
//a[not(@class)]        匹配没有class属性的a元素! v" X# w+ I2 f( D+ {% Q  u
谓语+ Q3 N" x  p. ^+ d! m' d
带谓语的路径表达式
$ A  d8 D# [$ _- f
# v" }2 U( u- ~$ r' C9 }7 W4 z! f: H

4 Y% E6 j0 u) [# Q4 \/ y路径表达式        结果
( s1 b, S& ~2 e: A/bookstore/book[1]        选取属于 bookstore 子元素的第一个 book 元素。
) L$ [# S% n9 E: j5 h/bookstore/book[last()]        选取属于 bookstore 子元素的最后一个 book 元素。8 g7 b; g' s& Z( b' T+ ^- E3 ~
/bookstore/book[last()-1]        选取属于 bookstore 子元素的倒数第二个 book 元素。
& x0 E" {1 z& T. Q/bookstore/book[position()< 3]        选取最前面的两个属于 bookstore 元素的子元素的 book 元素。' Q' h9 ^2 H  A; h
//title[@lang]        选取所有拥有名为 lang 的属性的 title 元素。4 w% W8 T" \$ [: e0 y' X+ d( \
//title[@lang=‘eng’]        选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。! m- b! ~: J5 n3 n
/bookstore/book[price>35.00]        选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。, @. ]0 p# X3 W) q
/bookstore/book[price>35.00]/title        选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。1 x0 g" B+ v( M0 T/ M/ r$ h
————————————————2 u: v- \) ?, \; [7 @5 n
版权声明:本文为CSDN博主「北山啦」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。: ?6 _  s! F1 d
原文链接:https://blog.csdn.net/qq_45176548/article/details/118187068# O# r# A# R' D% Z  C: G: w
8 ?) ^8 l# d# D, P9 `1 |7 _6 g

3 r) @& t8 \$ k7 Q2 X
作者: 1051373629    时间: 2021-8-15 17:54
厉害厉害厉害厉害厉害厉害   感谢" h3 v, d, P" j/ f

作者: 1051373629    时间: 2021-8-17 17:08
厉害厉害厉害厉害厉害厉害  
$ Q$ _2 \7 c, c- Z$ V$ b7 `




欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) Powered by Discuz! X2.5