3 b2 K2 K$ n, h0 s7 v. a, Y1 F8 G% J: A3 H+ H. T* E6 ~! q
e1 ^9 d& o. y# S N手把手带你5分钟搞定爬虫(聚焦爬虫) - B& }% R1 d5 k, z" m, y
2 R+ S { a s; B# r: L爬虫的原理
* v0 n3 @' |" R& c4 _4 M" L/ t4 j3 S0 @, ?
对于很多刚入门的小伙伴来说,了解爬虫的工作原理是非常重要的。只有当你了解了它的原理,你才能结合实际情况写出对应的爬虫。下面我将以通俗的语言方式来介绍爬虫
6 v4 }* m5 F. f1 F) s, Z把互联网比作一张巨大的网,那爬虫就是这张网上面的一只小蜘蛛,在互联网上面有很多的数据,各种各样的数据,我们可以把这些数据比作是被网粘住的小昆虫等。爬虫的作用就是去找到自己喜欢的口味,然后把它带回家,可以储存起来,也可以马上享受美味
- \5 o2 W; C7 a/ l' Q所以说爬虫分为三部曲:
h3 m6 c# j9 [! h9 c5 }/ n1、明确你自己喜欢什么口味(制定需求,明确你需要的数据类型)
4 ~4 D$ F7 e4 z; _2 {% ^2、去找到你喜欢的食物的位置(得到目标地址)
5 d' u6 b, ?$ m1 V9 A! {" y3、把食物搬回家去(解析网址,获取数据,存储数据)3 k5 A' A u8 Z5 _" S
它的整个流程就是:(简单的通过request请求获取数据并解析获取数据。以下都是固定化格式,可以照搬)
* z7 S9 P% E6 E7 ^& da、导入需要的库 requests% O1 z2 r# o0 M3 _
( @+ l- t& N9 N! Bimport requests
- k& N/ \9 n# w$ F12 {+ W6 n9 ~4 E- G: D
b、明确你要获取数据的网址(这里以百度网站为例)/ q6 c0 e y# R) c* c: t
' u! M. J6 Z( ~& [' v- R- m
url = 'http://www.baidu.com') f: v$ u6 l) \
10 n2 ^+ [; }& ]
c、创建请求
: y; n# F0 J) |( D, X; Y6 I+ b# ]3 \
response = requests.get(url)
# `' ?8 ?$ X# u; [* ?& V) Y% X N. H+ J1
: \0 K; b }* S4 d5 t+ Jd、测试请求是否成功(在实际应用中用的比较少,正常情况都是可以请求成功的,网站对于访问外部信息的爬虫是不会做出限制的)
4 [! o: @6 g7 w1 e' P, S! N0 Y
6 C) G! l& L! n$ pprint("状态码:",response.status_code)
( D7 E2 Y" W' l0 Q! i8 i% W1; s0 _) Q Z# x! l& L' p# v# m/ T
当状态码为“200”时表示请求成功;如果不是“200”,很大可能就是你的目标url写错了,核对一下url
5 a3 N0 i9 A6 d* p) fe、得到网页源码
& e+ w; x9 L- q! s' |
' l: Y/ u( k2 d0 H% N2 B! {; p. Nprint("内容:",response.text)
/ g5 J9 b; E! g0 L8 q1 K1" H' f' q5 ?* ]% O
response.content是response.text的二进制形式( J# Z. A0 r8 U
4 I c0 L' n: l* x: L至此,一个简单的爬虫请求就算是完成了。
# B9 N/ H( F* D! {! U当我们请求目标url并获取到response后,就需要进行下一步:解析网址并获取数据( s" e( R4 t8 s e8 E0 S
f、解析网址& l$ z0 D( [) }+ d8 T7 u, _* |
刚开始学习阶段,我们最常用的两种方法,一种是BeautifulSoup,一种是etree。其中BeautifulSoup是最常用的。以下将对两种方法分别进行介绍 (以下方法均为测试用例,实际当中应结合自己的实际情况选择应用)
4 @6 g! G0 o2 L3 o5 a4 ]6 QBeautifulSoup:" q4 {. p- V3 t0 ~1 l
首先导入需要的库文件:
) c" ]' i& q5 L; T% D% C* `
7 E B7 M) W, q: \# B/ vfrom bs4 import BeautifulSoup
! @0 W$ K4 T y, R) |1 a a1
7 H- d8 q2 [5 {然后对上面请求得到的response进行解析:) E0 S/ C; n. j8 V3 @
2 A2 }' S+ J( zhtml = respone.content.decode('utf-8')# [8 w; U- D7 t
soup = BeautifulSoup(html, 'lxml')& c& y# d- j5 X$ I
1+ _& D# v4 W: e" O
21 d' L1 I2 b- y% z8 r- O3 w$ Y
以下是BeautifulSoup中比较常见的方法,有兴趣的朋友可以去一一测试:1 y/ V4 F- v1 D' a: N
# 获取head标签" a, _+ B1 C2 {/ B7 m# O
print('head标签内容', soup.head)" Q7 W" S* f3 Q7 z8 I) ?4 p
# 获取title标签 }* a5 T) T, p) T: _
print('head标签内容', soup.title)8 p5 l& d7 u/ e+ z
# 获取body里面的img内容
y/ _3 N+ q' [ ^# 通过点号的方式只能获取 下属第一个标签(即获取soup下面第一个body里的第一个a标签的第一个img标签)$ K8 K* K$ A$ y. \# t& e
print(soup.body.a.img)
3 Z* n2 }% D: g, M9 J8 r& w# 获取所有的img标签 使用find_all()搜索整个soup对象" G" @" t( c s4 J) ], u7 H
print("获取所有的img标签", soup.find_all('img'))
' A; ^2 l& D9 S( P% m# p4 `4 K8 _# 获取标签中的属性src地址0 ]6 u% A# w9 k: r9 b
print("获取标签中的属性src地址:", soup.img['src']) # 注意:英文点号都只能获取第一个值
# H- c& j- d6 n; p' u7 n0 Q
& n3 Q8 o9 z3 H/ c c% s
5 m+ T7 N( l5 w* m% b" ~; E# 获取soup的name" _% |. _. Y. n# Q7 H
print("获取soup的name:",soup.name)+ b, S- i+ E! W9 e
# 获取a标签名
; t' ~( Z m4 _+ iprint("a标签名字:",soup.a.name)
3 L1 G* c& P$ d! r- Jtag = soup.a2 X) C1 r3 ]" H. r+ U4 w+ s+ x
print(tag)
' J% d! O( f# D# 修改操作 a标签改为b标签- }9 ]- Q) R9 e( j& ?* g
tag.name = 'b' # 赋值后<a> </a>变为<b> </b>
% U) z, z. R0 h4 l/ w: c6 |# 输出修改后的内容
+ T6 w% D" f& } Oprint("输出修改后的内容:",tag)! w; c' f0 C1 L! Z, c4 f$ @/ q
# 获取全部的属性 attrs r L1 S Z+ {) u
print("tag对象的全部属性:",tag.attrs) # 只能得到当前标签的属性(不包含下属标签); R8 Q+ B" c! B- g0 ]8 V
; I4 z; Q: u3 ?8 ~5 p0 N9 m9 W
# 获取属性的class的值 根据键取值0 l5 q8 L5 y2 t; u7 U9 z
print("获取属性的class的值:",tag["class"])$ p- P( h7 a* a! w6 |
# W i: m) i/ g1 i
2 r1 u7 V) B2 o1 {# R
9 D# w; K+ M$ }6 x$ q, T4 f: C5 T; K- a4 M2 Q
"""针对获取的标签属性可以进行增删改查"""4 g4 Y3 V Q* ^
# 修改
3 l+ U9 i" `# x/ ttag["class"] = "Logo"
! @8 C2 c$ H! y4 e h# Eprint("tag对象的全部属性:",tag.attrs)
3 x5 V# P% Z" G5 C1 |. o& Q2 ^# 输出属性
7 M& p9 P( I- q: {7 B. Z5 _print("获取属性的class的值:",tag["class"])3 X* x, j' Q* V7 g
# 新增 属性id 赋值logo
6 K# G4 |9 A2 s/ _8 mtag['id'] = 'logo'
% `* U" Z; Z# g; g3 G5 qprint("tag对象的全部属性:",tag.attrs)* y* o0 m0 ^# e$ `" E( D+ h, _% V
# 删除属性- a( G# U4 B; m& G5 j
del tag['class']
2 h# w4 W4 p) G7 m sprint("tag对象的全部属性:",tag.attrs)1 b( e9 [; X: d1 ?& ?4 O( S7 n; I
' I8 q2 T! O Y6 F" [ y
9 A7 O, X# X/ ]6 B# q+ v7 h
- y+ D* \, y& L% N9 F3 u0 b"""针对内容操作 (只针对标签,对属性无效)"""
, e ^) p) f/ q$ B* b6 x# 获取title标签内容: m8 S" M. W V2 w; ?
tag = soup.title& R% x" H, p, J) t4 r! q% } i! [
# 获取title字符串: r. D% q3 p- \- A
print("tag对象所包含的字符串:", tag.string) f3 I5 [* ?2 @0 O
print("类型:", type(tag.string))' A/ A4 D! p1 U
# 替换内容
( n7 l! `" T; n! R: otag.string.replace_with("你好")
4 R2 `. l5 ]- e6 c, c* Uprint(tag.string)6 U: P; H; f( V9 Y9 b) \3 U: z
# <!-- 学科建设 -->
; J7 k* p$ A" D2 o- p4 e y; j1 I3 k8 {# 获取注释文本内容& Z: r. F0 ^8 n2 k" L
markup = '<b><!-- 学科建设 --></c>'
( ^; Y; ]. s C' Qsoup_comment = BeautifulSoup(markup, 'lxml')
( r; U& E0 A# fcomment = soup_comment.b.string # 以markup第一个标签作为关键进行搜索
! ]5 y* U! M4 Y: w7 B. m# t: qprint("获取注释文本内容:", comment)# o' r% l$ x" z# w$ H) {
# get_text()1 }( I' E& e8 I0 U4 v% f
print("title的全部节点:",soup.find_all("title"))
: Z' q4 s# f X% P, rprint("title的内容:",soup.title.get_text())
+ n' z' l6 Q S; n% }"""查找ul元素标签""" ^$ G. m# B; D# D, D8 @
# class是关键名,匹配时后面必须加下划线_
# V$ h" a$ b, R( S- c5 L# tag = soup.find_all("ul", class_='menu') # 按照css类名完全匹配
& H2 u b/ H7 v, L% y# print(tag)
; l% X. I7 t' t. G$ C1 c# rtag = soup.find_all("ul", id='menu') # 按照css类名完全匹配) A+ N' ?- g+ J4 g
print(tag)
# L5 H# h* m: ~* Z o6 u# 查找名称为a元素的标签内容0 c( f* R. q" P) F; d: `0 e' e
taga = soup.find_all('a')
* H2 d/ I, V" I# o2 Wfor tag in taga:9 w# R- v, C. I6 @( M- f2 m. e2 m
print("查找名称为a元素的标签内容:", tag.string)1 q0 _0 @. C' e/ `! F4 b) `# O2 A
# get 获取属性信息 获取整个页面的img标签图片和src属性值 z" T+ d/ j) Z
tagings = soup.find_all('img')
( Q! D ^" M% a% T, `print(tagings)# {3 _0 R2 l3 K. I3 w
# 循环输出图片地址
: B9 [; y" }; n. X, jfor imgsrc in tagings:2 T- z: Y2 }. Q
print(url+imgsrc.get('src'))8 i" @' |8 T' r' _ E
! D4 _& p' J8 e5 _. N""""属性只能做为参数,所有的操作只能针对标签"""/ B N6 i- q/ e4 Z/ _% s
; G3 [2 Y! B5 U7 T% J; Z
etree方法:5 P5 G6 M2 f( v+ R' U
导入库文件:* `: `$ B. b( P2 j" \
9 F6 O6 g4 U9 b% _% [9 V
from lxml import etree2 f) a W `9 s H, @) W
1
3 \+ A: _8 M( z9 ]6 B解析得到的response对象;
* `! R+ @* z6 R
5 G1 R1 E% N7 E$ q0 q# 设置response的字符集
3 I/ i' f5 ?0 g- ^html = req.content.decode('utf-8')/ d$ \6 |+ {+ G! f) r: q
# 解析对象
4 u3 d4 E. c7 }/ J) J( J; Ghtml = etree.HTML(html,parser=etree.HTMLParser(encoding='utf-8'))
. W8 n4 y1 t; X, e0 n1 [* d) H
0 l. Y7 ~7 Y) s/ U, ]2 c1 |常用的方法:
+ y3 O) b2 A$ s, p
) m' s5 m i/ g3 m' V' G' B6 s5 E6 L6 B# i& X0 j
# 定位head节点(元素)' M$ N1 @! L4 N
result1 = html.xpath('head')1 p x& u' E2 C1 N6 I; _
print(result1)/ S3 ^6 z8 ^- r0 |; ~
# 定位title节点# j9 g5 Y* M: j4 x% l q
result2 = html.xpath('/html/head/title')% b6 r/ G& C/ P1 s3 w
print(result2)
' y; y9 C- t' U- I/ O% a2 ~9 W# 搜索节点 title节点6 d6 Z, ?4 F; t7 M3 W. Q! Z
result3 = html.xpath('//title')
0 D' g/ h5 T+ B oprint(result3)
- C! R% I/ M; p8 r7 G* a8 S# 搜索title内容 text()得到文本信息
4 D E& z3 l( o: I& `5 {, Tresult4 = html.xpath("//title/text()")/ W9 Z2 L* ]5 ~$ Y
print(result4)2 E: R8 c/ `: D; W0 ~0 M' T3 E
# 搜索div节点1 G& @8 r' U' I$ p# o/ Y! [
result5 = html.xpath('//div')
; {9 g9 N* b( Eprint(result5)% T: c5 V* }' M" O+ v& l" s+ i! d
# 搜索div节点 并用class属性定位 L: o6 C! ~2 f! O, w4 |! ]$ D
result6 = html.xpath('//div[@class="news"]')
% L2 s3 ?# j- N8 }# \4 tprint(result6)! {8 L* Q6 b& Q6 f/ x S6 a- ? K9 U# [
# 搜索div节点 id属性定位
- T4 l; G: S$ r1 F* k. J8 g- z" hresult7 = html.xpath('//div[@id="news"]'); @8 b8 v1 R3 V1 q. u! h
print(result7)
/ J; g. w: k0 n4 N# 获取列表span信息
& @( I% D* C F" ftext = html.xpath('//div[@class="news"]/a/span/text()'); m+ [) G1 W; Y& @' P1 S, b$ R
print(text)# C p; e5 H/ g, f& c* o' @0 V$ ~
9 j J, Z- S0 ]% G) ~! {& v, O4 C
g、通过上一步我们得到自己需要的数据后,下一步就是将我们得到的数据进行保存
- h8 e x3 g' ]% V# r% O* l保存的方式有很多种:: ]8 t& }/ O# ~ l: P
1、保存至文件
, A/ C, _; U/ U! k& M7 y3 hcsv、json、text
$ D7 g0 h: U2 D; R$ o2、保存至数据库
# Q8 A4 w& t1 Y" r KMySql、MongoDB、Redis 等 (目前主流的为以上列举的三种数据库) 关于数据存储后面再做详细介绍$ x% W2 Q" p) [. g2 e& u, H' q
( y$ n8 o- R5 ?% m" B+ \, p+ ~9 L
9 I! C+ C0 l+ Z, }; U————————————————/ N3 X2 F# j7 ]# ?7 n
版权声明:本文为CSDN博主「royallucky」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。5 g9 }/ W, j1 d3 @6 K4 a
原文链接:https://blog.csdn.net/royallucky/article/details/105930473
1 A% n1 Z. `. E/ h1 `
. F5 E: u( F0 [: q3 ^$ Y. O& i: T# S
* J% k6 w# q- n0 B7 P9 t |