, m$ K. \/ h) D; X
% r$ g1 {; d/ { * g! Z% N) \1 i
手把手带你5分钟搞定爬虫(聚焦爬虫) " n4 x, |4 B; r8 k3 Y/ C% Z) L
; c. K a- _: q: Y5 f! z+ U$ F
爬虫的原理% q5 q$ Y! r; A" j- }% ^4 G
+ g+ d* [) D7 b$ b对于很多刚入门的小伙伴来说,了解爬虫的工作原理是非常重要的。只有当你了解了它的原理,你才能结合实际情况写出对应的爬虫。下面我将以通俗的语言方式来介绍爬虫
; Y# K: S% o. p" O) x把互联网比作一张巨大的网,那爬虫就是这张网上面的一只小蜘蛛,在互联网上面有很多的数据,各种各样的数据,我们可以把这些数据比作是被网粘住的小昆虫等。爬虫的作用就是去找到自己喜欢的口味,然后把它带回家,可以储存起来,也可以马上享受美味; D, S4 R+ c, | u$ o, e G
所以说爬虫分为三部曲:
' `4 x; c- U; P8 T9 }1、明确你自己喜欢什么口味(制定需求,明确你需要的数据类型), i* z- q4 _% m6 T" w2 T
2、去找到你喜欢的食物的位置(得到目标地址)
M6 |7 L3 i7 c' O; P) G0 J, J3、把食物搬回家去(解析网址,获取数据,存储数据)
5 T3 i0 B$ \5 x! ?5 z它的整个流程就是:(简单的通过request请求获取数据并解析获取数据。以下都是固定化格式,可以照搬)
+ v$ f1 B# Q% G/ y% Oa、导入需要的库 requests
6 V. J( a' {* t& Y1 }- ~, U% Z- r H M$ P: e1 ^; L! W5 v @
import requests* ]- k+ G. p4 |# ?7 _
1
' R0 M0 c' m: g% \9 B6 R9 k& [b、明确你要获取数据的网址(这里以百度网站为例)/ N4 v/ g( h" Y+ P+ ]
& C+ \8 V- d* h4 z
url = 'http://www.baidu.com'
- X3 T5 Y5 W a& V0 l# c0 Y2 H1+ A4 U( I( @ [( n
c、创建请求
. M( D/ ^9 T5 f; i
5 F) r4 `4 u: p3 {$ L7 D( B' H+ @response = requests.get(url)
0 k9 p- _ D1 `; @$ n7 t6 H& s# r- e1
6 Q8 K( B3 ~0 R$ ~6 B, Ed、测试请求是否成功(在实际应用中用的比较少,正常情况都是可以请求成功的,网站对于访问外部信息的爬虫是不会做出限制的)7 g5 V3 j; y3 B- H0 E7 U
Y7 h, u m. [: G- s, ]print("状态码:",response.status_code)
], f3 z+ @/ {7 K$ Q: O5 b1
7 u# ~: u3 X" f7 f/ i当状态码为“200”时表示请求成功;如果不是“200”,很大可能就是你的目标url写错了,核对一下url5 w! a; D1 T" e6 b
e、得到网页源码; {, O# \ w0 r' F& l
: _- X7 _+ ?: I6 h8 x7 V& iprint("内容:",response.text)
$ W3 e2 }2 q2 x H: y# D2 _$ n$ Z1
# r; U: Y& [. f- T3 m0 Qresponse.content是response.text的二进制形式
" g5 T" F$ |0 V! j
' ~% Y- }7 J, n$ r) l至此,一个简单的爬虫请求就算是完成了。
4 l0 m& y( o: z; U+ X当我们请求目标url并获取到response后,就需要进行下一步:解析网址并获取数据! v$ x& ?" O( {, g* _; w- M
f、解析网址
. s. c7 k) h. |8 f5 w& I刚开始学习阶段,我们最常用的两种方法,一种是BeautifulSoup,一种是etree。其中BeautifulSoup是最常用的。以下将对两种方法分别进行介绍 (以下方法均为测试用例,实际当中应结合自己的实际情况选择应用)! w, k+ m! h/ |
BeautifulSoup:
, a; Z2 b9 v5 @6 W% s首先导入需要的库文件:: t- K4 m+ Y3 V" x
7 n7 R4 C6 H: i/ b7 M1 q2 \2 ]
from bs4 import BeautifulSoup& Z$ w7 x) o! O2 O' e5 S* @* F
1
" D6 ]: M7 {* S3 T% N2 E" ]然后对上面请求得到的response进行解析:0 F; D- j. s! A5 L2 z( o7 I9 V
- C/ X( B+ L* B& E, b2 }& d
html = respone.content.decode('utf-8')- v4 a7 d% \' z2 l e* u
soup = BeautifulSoup(html, 'lxml')( v: {* h. J' G# w7 l+ m4 b1 G' J9 G
1
5 i: o8 ?9 s$ ] y* S& j# V; V2
& J) g$ g# `$ g, N8 {以下是BeautifulSoup中比较常见的方法,有兴趣的朋友可以去一一测试:( U R4 m/ F- i5 u) ?; w1 g d
# 获取head标签* \' Q1 b9 R; ~* P& S
print('head标签内容', soup.head)* N# b+ J' W/ V# \2 @7 M
# 获取title标签
8 |3 b9 ~" H2 C! }" nprint('head标签内容', soup.title)2 s4 E7 g/ D3 B3 S# D0 [) ^+ H
# 获取body里面的img内容
2 |; v0 P. S3 x' e- f7 w' l. q+ G' Z# 通过点号的方式只能获取 下属第一个标签(即获取soup下面第一个body里的第一个a标签的第一个img标签)
7 n( L8 T% f9 Q5 E; |1 Yprint(soup.body.a.img) 8 x! ^% x, Z$ R0 [6 i) M
# 获取所有的img标签 使用find_all()搜索整个soup对象
1 Y) z1 s. G6 b( a5 ]7 X, Xprint("获取所有的img标签", soup.find_all('img'))9 d$ G# f: Y8 j/ x+ T+ t+ H: x( G
# 获取标签中的属性src地址' v) [9 h8 j: D) S4 P
print("获取标签中的属性src地址:", soup.img['src']) # 注意:英文点号都只能获取第一个值
9 n- P, @ Z$ b; A: x
T6 p& [$ O5 K, q
: @6 M1 h' ?* N# 获取soup的name$ g, t1 m$ W0 Z, R
print("获取soup的name:",soup.name) p4 R3 X2 c8 ?% a' I7 O
# 获取a标签名9 K& k9 Q) z( X0 s' N- B8 s$ y. `
print("a标签名字:",soup.a.name)0 a) b& Q9 o! _. C, n* F3 C3 N7 F
tag = soup.a
+ z- T1 W+ h, z9 Z0 Gprint(tag)
( ~8 g8 I2 {( q d0 H/ I6 g# 修改操作 a标签改为b标签- o: _, l5 G7 ~) I8 U( R/ V4 Q
tag.name = 'b' # 赋值后<a> </a>变为<b> </b># a4 e8 d& y# Z
# 输出修改后的内容
2 ~. T' H2 h( g" `% k( m) x2 eprint("输出修改后的内容:",tag)6 V# ?/ w( G7 o, z
# 获取全部的属性 attrs! @! R/ V8 `; C+ N7 `3 f
print("tag对象的全部属性:",tag.attrs) # 只能得到当前标签的属性(不包含下属标签)( c% \' h5 S |5 b2 ]
. s/ e/ X( a8 [% _! f; G# 获取属性的class的值 根据键取值
! j; H6 Z8 Y& W, Y2 o4 o0 oprint("获取属性的class的值:",tag["class"])
4 P4 q9 e$ g5 u# N7 H& @( W ^' M4 M2 H
; d1 e8 O9 K- R4 t/ \
! P% z \7 i! I4 J4 N
" k8 B, ]) {8 O$ G& I& ["""针对获取的标签属性可以进行增删改查"""* j! i8 t; \2 m/ r5 x# u( a( B
# 修改" l2 ~; e& S8 a. Y6 t+ b7 m% @8 T
tag["class"] = "Logo"
7 d4 _% [% Q2 Iprint("tag对象的全部属性:",tag.attrs)
' ~4 `; y: ?' w# 输出属性
" K* H+ R- V; i; o1 o/ M$ G7 Fprint("获取属性的class的值:",tag["class"])# k' N7 z L1 r3 `5 }
# 新增 属性id 赋值logo
, c: ^3 h$ d, A6 f" L( otag['id'] = 'logo'# z i6 R3 E- ]! d
print("tag对象的全部属性:",tag.attrs)9 W* {. x8 U6 T* r* [# D0 Y5 I
# 删除属性
% f' }0 _: D# {) bdel tag['class']
% c& I( A# P' s- f0 J! [' ]print("tag对象的全部属性:",tag.attrs)
p% X2 H' K/ T* ^) O. c/ Y* u. x) L5 f `5 \
% b% O9 a! }# _ n3 ^4 F& z3 v4 U
"""针对内容操作 (只针对标签,对属性无效)"""! }5 N8 w9 Z- O, j7 W* J( V% b
# 获取title标签内容4 O( }# H: A# d9 q# _
tag = soup.title
: I* i6 N0 v1 |9 P) E" W9 Q4 f# 获取title字符串/ |( |( ~# u* e, M7 R9 @7 I Q
print("tag对象所包含的字符串:", tag.string)
3 `2 Z, \7 K5 p/ c8 Cprint("类型:", type(tag.string))! s. L- G1 w7 A: f% \( I
# 替换内容! m2 m# E. Z# _; Y/ P; i
tag.string.replace_with("你好")
@ {8 X% p) _, F: Q& r# sprint(tag.string). k! O6 e3 [6 N" G
# <!-- 学科建设 -->
* o& ^8 _5 p4 p8 N# 获取注释文本内容8 ~& {1 d/ y7 n1 n# L( t* S, m
markup = '<b><!-- 学科建设 --></c>'
" x" o% c* O. U# s+ O Lsoup_comment = BeautifulSoup(markup, 'lxml'); G% E! E8 ]9 z6 y9 A
comment = soup_comment.b.string # 以markup第一个标签作为关键进行搜索
; j1 }5 g3 I4 A: y3 oprint("获取注释文本内容:", comment)% Y9 C" _$ D% h% k! r
# get_text()
6 P3 m2 J& j8 u% @, t9 _print("title的全部节点:",soup.find_all("title"))
' F* ?7 n% ~4 t4 V- eprint("title的内容:",soup.title.get_text())
" H( ]# m0 n0 |0 K# v; }"""查找ul元素标签"""
+ L6 f# A" u' [' D; D$ ^& p# class是关键名,匹配时后面必须加下划线_* ?- p4 A$ x- p4 M
# tag = soup.find_all("ul", class_='menu') # 按照css类名完全匹配
1 Q! f5 P& X: g+ z# print(tag)
# ^. \7 s+ l5 b% M2 |$ ]: vtag = soup.find_all("ul", id='menu') # 按照css类名完全匹配; v! L) R P2 l/ @
print(tag)
- l9 A( e( {, [2 K# 查找名称为a元素的标签内容
2 Y* U' Y# Z0 P1 U3 \! ]3 [taga = soup.find_all('a'), e: z+ G c% i
for tag in taga:
0 v0 ^5 P; k& N/ q3 s8 m print("查找名称为a元素的标签内容:", tag.string)
( a2 F+ t1 n1 e5 Q: d# get 获取属性信息 获取整个页面的img标签图片和src属性值
$ W0 `, w% a( V$ {% Vtagings = soup.find_all('img')
# u( b& t" M" r/ ]' H9 rprint(tagings)
/ O+ K5 G6 u7 W& Z" ?# 循环输出图片地址
% D6 ?" e: i! p/ M# d! y2 Jfor imgsrc in tagings:; o) A& z1 Y0 p/ a! ], N
print(url+imgsrc.get('src'))
$ H" K( z+ Q8 g9 ?
9 @4 J# [- c0 @. m""""属性只能做为参数,所有的操作只能针对标签""". m M) W6 @1 B
0 b1 \ h0 W# Y% e* m
etree方法:1 n, p8 e6 c4 @4 n: Q3 Q, v5 |
导入库文件:6 a0 E1 y$ \- Z2 u7 \) F W
4 X I$ _6 v, C3 P8 {& V+ bfrom lxml import etree: L1 E. b& r P0 g. U/ [9 E
1
/ v; N" Q! u$ C( M8 z解析得到的response对象;
" k! B X5 Z* T8 t( S# C: b, k" U! X. t9 E$ z& R
# 设置response的字符集
2 N7 d' R+ |* b- Z- x/ Y3 ~html = req.content.decode('utf-8')% G6 t# A: E1 x' B; T8 m/ Y" L! Z
# 解析对象% F6 M1 \. v+ ~+ U; E
html = etree.HTML(html,parser=etree.HTMLParser(encoding='utf-8'))0 r3 y' N; }" f) f/ c) d* v
4 f* M& o Z; p4 X; o) c7 S
常用的方法:) o& c1 T3 @9 r( `4 {$ T7 n
: |% f, S2 \* m" o
W3 A0 x {# t& j% _) l
# 定位head节点(元素)4 Z# B7 l3 B' i, w2 J: v
result1 = html.xpath('head')+ z8 l: B% B: V3 @3 U: f/ c% m
print(result1)
) b! D9 F- h. a# D# 定位title节点
9 k: q; \: K+ D$ P2 i* l8 }result2 = html.xpath('/html/head/title')( P0 l( p6 O* A/ z& S
print(result2)
( G# s) U6 H8 @) J; n# 搜索节点 title节点
' F4 K) Q# B# w1 F3 q) P3 S8 @result3 = html.xpath('//title')
3 X" [" b2 W' O9 G- m( r+ zprint(result3)( z: _! }& N+ I5 s, n' E
# 搜索title内容 text()得到文本信息$ U- M; C$ [. G( D
result4 = html.xpath("//title/text()")3 z: j, u9 a4 @1 e2 y% {' o( E: z
print(result4)2 ^, O, E9 V' d' R5 q# C# _) X% M
# 搜索div节点6 T' [- W- F' |( O3 w; O
result5 = html.xpath('//div')5 Z1 k& l4 ?! G3 B" C
print(result5)
; V v& c3 E: \: }8 `" {# 搜索div节点 并用class属性定位7 o) E' U# x c& b, R4 s( O# w
result6 = html.xpath('//div[@class="news"]')$ [# i3 M m- R! z* \9 |
print(result6)
* x. A7 k" g9 e9 D# 搜索div节点 id属性定位
1 B! C" O, J2 l5 m( s! Q4 _; e# cresult7 = html.xpath('//div[@id="news"]')7 D/ Z/ }, Z1 J' Y
print(result7): r) J* n% r4 B/ U! t
# 获取列表span信息! i2 \2 B4 s- X) f
text = html.xpath('//div[@class="news"]/a/span/text()')6 X+ h0 @4 a0 I V k: ^ a: w4 t% U
print(text)
0 Q) O" A3 V5 a V) S0 d5 f" W% M
" [( C1 y$ {/ U: h* Xg、通过上一步我们得到自己需要的数据后,下一步就是将我们得到的数据进行保存
( M& l; V1 f! O7 j, K! f/ U, Q" A保存的方式有很多种:
8 L6 J2 h2 t3 T& ^7 K1 {% k/ D7 Z+ X# A1、保存至文件1 u X+ y- T" H$ T7 w7 M7 T
csv、json、text' p& i- w( O0 A, b+ ^4 @
2、保存至数据库8 w7 y- l U! K8 h( I- H4 \+ z
MySql、MongoDB、Redis 等 (目前主流的为以上列举的三种数据库) 关于数据存储后面再做详细介绍
- j& A/ n; U0 e& ~5 o' I0 m0 K3 `+ [6 \* w( v& N) J
- F5 u( j' q( _————————————————
6 M3 A1 r- B+ l9 ?版权声明:本文为CSDN博主「royallucky」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
+ R8 X; B$ Z- u& |% C原文链接:https://blog.csdn.net/royallucky/article/details/105930473; b1 u7 ~7 F* I3 c# i) V( q
* _' J5 A+ d0 j7 @
+ C$ T8 Y3 }! u
|