! a& X- c; Q, [1 l" B3 E, s4 ~8 q+ |
; y5 U. \* a k6 l- G+ p1 c
, W2 R- O8 ^6 d1 W+ R! ]- {. N5 X
手把手带你5分钟搞定爬虫(聚焦爬虫) 0 x- L0 w2 ~3 E$ c9 F- ~, n
0 s, J$ ^/ J, \
爬虫的原理
8 r _& t7 a/ n$ s& _3 H: R ?
% R+ _3 u: a2 v0 N8 r% |对于很多刚入门的小伙伴来说,了解爬虫的工作原理是非常重要的。只有当你了解了它的原理,你才能结合实际情况写出对应的爬虫。下面我将以通俗的语言方式来介绍爬虫
' N. {- `& A3 a2 H% u把互联网比作一张巨大的网,那爬虫就是这张网上面的一只小蜘蛛,在互联网上面有很多的数据,各种各样的数据,我们可以把这些数据比作是被网粘住的小昆虫等。爬虫的作用就是去找到自己喜欢的口味,然后把它带回家,可以储存起来,也可以马上享受美味
9 O7 @7 A$ G5 V所以说爬虫分为三部曲:
3 f. g* C' b Y, ^9 I, }9 T, o& L1、明确你自己喜欢什么口味(制定需求,明确你需要的数据类型)2 ~& n1 {! B5 I
2、去找到你喜欢的食物的位置(得到目标地址)8 C* C3 a8 u) d5 m) u& p; \
3、把食物搬回家去(解析网址,获取数据,存储数据)
! k$ ~/ q G7 t! d, a& {' P它的整个流程就是:(简单的通过request请求获取数据并解析获取数据。以下都是固定化格式,可以照搬)7 ~$ n' E: q* w4 o( p
a、导入需要的库 requests
( p3 {- |( M) r! w
$ d3 `( T Z5 U8 X0 ^3 |import requests1 e4 E2 `. F5 d7 o2 u
1# t$ u9 M& n/ r2 Z% ~( H* _; m# A
b、明确你要获取数据的网址(这里以百度网站为例)
, N/ o9 k! `0 a- J, O/ P+ ^* f
url = 'http://www.baidu.com'
, Y- x- \) F; r% o6 k1
- S8 l* o+ q8 q+ ?. Nc、创建请求% J& y* y* G2 k$ X% C ?4 P6 S# r
0 R0 q3 M' p' e' ` W- \response = requests.get(url)( n5 I6 E! O/ d! l( |
14 @9 l" a, Y A
d、测试请求是否成功(在实际应用中用的比较少,正常情况都是可以请求成功的,网站对于访问外部信息的爬虫是不会做出限制的)
" D: P) S {; Q1 {3 k# G* c
4 i# ^; D+ d: r8 Qprint("状态码:",response.status_code)1 d6 M; n: O2 R- d" M N7 ^( o
1- {; C P( j7 r
当状态码为“200”时表示请求成功;如果不是“200”,很大可能就是你的目标url写错了,核对一下url
& I: r& L5 l1 f2 T8 Se、得到网页源码7 M! }2 i8 y. k/ {7 P3 ?
% X1 { U7 w1 W" f3 J+ N" q
print("内容:",response.text)/ ~8 P; _# `4 h1 z- k6 \' V6 g" Q
1# H% R5 l+ |2 V. Q' S
response.content是response.text的二进制形式
* Y, e+ C5 V/ A' L. g0 k6 N, c
9 E( y% m1 P% x1 F# L3 Y- Y至此,一个简单的爬虫请求就算是完成了。
4 B7 d1 o* F9 e1 O当我们请求目标url并获取到response后,就需要进行下一步:解析网址并获取数据
2 y4 T8 @' t4 X2 I+ \- `f、解析网址
5 m! F! \2 [! b! |- v- d刚开始学习阶段,我们最常用的两种方法,一种是BeautifulSoup,一种是etree。其中BeautifulSoup是最常用的。以下将对两种方法分别进行介绍 (以下方法均为测试用例,实际当中应结合自己的实际情况选择应用)0 V4 ~# U* d/ Q% ^% v! z- [6 a
BeautifulSoup:
! c) i9 ]1 f8 I/ h首先导入需要的库文件:- ~) |, T0 g% C- Q
5 \: V" g8 ?+ M+ l9 Rfrom bs4 import BeautifulSoup
/ T# c) M; `& |1& {9 r& P/ {8 o& m( `. l
然后对上面请求得到的response进行解析:: A8 j8 |$ D- x) E" E% H
( o- C+ b+ @: C9 \( M0 t Lhtml = respone.content.decode('utf-8')
, F/ X0 B- R" i& C* {, n' ]3 E: ?soup = BeautifulSoup(html, 'lxml')
+ v. s" D9 A2 [: u- q# @1
, ^1 i. e7 \/ K" |/ L+ E25 ]3 U( N2 p( f% J4 I* U$ _& i
以下是BeautifulSoup中比较常见的方法,有兴趣的朋友可以去一一测试:) I1 c6 p3 d8 s$ p J& i% S
# 获取head标签
/ H3 z, k" ?5 X( e& ]8 y$ v+ [/ kprint('head标签内容', soup.head)) m& E4 k7 J+ h: k0 n# H" a
# 获取title标签, d1 |2 L" P+ ~/ ], [
print('head标签内容', soup.title)+ u% n R4 W6 J
# 获取body里面的img内容( l; }5 |, \5 {6 ]" M0 Z/ X
# 通过点号的方式只能获取 下属第一个标签(即获取soup下面第一个body里的第一个a标签的第一个img标签)
0 F. T# b0 Q( t6 ? o# x6 B% Uprint(soup.body.a.img)
* e7 N# ^ ]$ _% m( q: \# 获取所有的img标签 使用find_all()搜索整个soup对象
; l% P* Y9 k/ V8 Bprint("获取所有的img标签", soup.find_all('img'))5 T( z( i* c& J- X+ V# r$ O! W* N+ ?
# 获取标签中的属性src地址; Z8 v: ?9 }7 F& m
print("获取标签中的属性src地址:", soup.img['src']) # 注意:英文点号都只能获取第一个值
3 G+ s, d( b1 N( n" i: w
7 X! b b7 D3 @, ~
( s- H' l( k r8 z8 [5 }9 i8 @# 获取soup的name
! G5 x) g6 l4 L( ^6 d0 Rprint("获取soup的name:",soup.name)
8 _2 }2 T" t- R" \9 P# 获取a标签名
; B8 v: }+ L: u7 r6 @ \) j0 Sprint("a标签名字:",soup.a.name)
) a: r& y. m* M6 etag = soup.a
) W( Q6 Z5 E( o E: N% e- @print(tag)
, f: d" U+ f3 U3 j# 修改操作 a标签改为b标签
$ o1 Z) i6 }/ Y7 c; s+ r8 ztag.name = 'b' # 赋值后<a> </a>变为<b> </b>
& \- Z9 U T& u* v: |+ \, ?0 J$ G# 输出修改后的内容
: _7 z% O% ]; k' Sprint("输出修改后的内容:",tag)
. m7 @5 N& r2 R9 n. C# 获取全部的属性 attrs( r% V$ v- s, \: d
print("tag对象的全部属性:",tag.attrs) # 只能得到当前标签的属性(不包含下属标签)
' i6 t" B& ]( S d, H7 g
. N, y6 J5 U& ]7 Q# 获取属性的class的值 根据键取值
# s( c: A9 t3 f- j# Gprint("获取属性的class的值:",tag["class"])
9 x4 x# @ j, n/ h5 j/ I# }) M& T
0 G7 s' y7 X ?3 S
$ I9 y7 ?* i+ I4 ?8 n4 q9 m7 n) E: H0 p2 q/ K* B% ]6 M: s) c
/ i# e$ s5 u3 E9 \( A
"""针对获取的标签属性可以进行增删改查"""
1 j3 I& q5 ^5 N' o# 修改" L+ K5 w7 E* F" ]
tag["class"] = "Logo"
& D. u: ~. D/ y" bprint("tag对象的全部属性:",tag.attrs)1 _8 O. T2 v2 [: u
# 输出属性4 q# w! @# a' j0 K& @3 q0 _
print("获取属性的class的值:",tag["class"]): s+ A4 ]/ J z V
# 新增 属性id 赋值logo* G5 H/ j# e" y, N ?
tag['id'] = 'logo'$ G4 u8 a ^# y7 R( |% R
print("tag对象的全部属性:",tag.attrs)
K, Z) s, }4 j N5 M# 删除属性
* y) }+ N3 ~. y2 ~8 g1 s1 \del tag['class']; f8 U+ |0 _7 Q( u* K: ^; Z' p/ l$ j
print("tag对象的全部属性:",tag.attrs)4 @! z5 J7 S3 p0 d$ a! W$ m( H1 T
. R8 Y# Y4 [/ f" m
9 T7 n- N6 ~- i- q$ s' c
s7 n# F! A c0 o. u2 H"""针对内容操作 (只针对标签,对属性无效)"""# Y: ?4 ]- C0 m
# 获取title标签内容
) B% b- d" t( j8 _tag = soup.title
4 K. b9 K' G/ x- ^# 获取title字符串
. `$ B- ]0 k( W0 R6 q6 Jprint("tag对象所包含的字符串:", tag.string)& r5 c9 {1 m3 V3 M
print("类型:", type(tag.string))
% K M8 |! Q0 J6 ~# 替换内容6 R u* {. G7 g l) H
tag.string.replace_with("你好")' V) ~. z4 p* B6 D3 O: C: e' C& ]
print(tag.string)# R; F0 j" t5 G( X0 k" G c! a+ P: S+ Q1 h
# <!-- 学科建设 -->
- Y ^' T/ o# D0 m d# 获取注释文本内容
& O' K1 n( e) t% M) R1 g9 cmarkup = '<b><!-- 学科建设 --></c>'1 c0 r4 ^0 W0 {- Z
soup_comment = BeautifulSoup(markup, 'lxml')
6 r0 a v; K+ |" o% e$ l/ Pcomment = soup_comment.b.string # 以markup第一个标签作为关键进行搜索
9 L4 e8 s9 e8 C: h) aprint("获取注释文本内容:", comment)
! A: W: H3 C+ O! l$ A/ {* R# get_text()% [+ V- f4 l! i: y, Z! z+ ]
print("title的全部节点:",soup.find_all("title"))
. H! A/ A2 O2 o4 c# f. w( Q' b- k) Bprint("title的内容:",soup.title.get_text())6 ^: V$ m4 X+ `* H3 I" Q4 e
"""查找ul元素标签"""
, e! l) r& Z7 [& ]9 j* i# class是关键名,匹配时后面必须加下划线_
8 _1 M$ _! d) F3 @+ _9 y6 O# tag = soup.find_all("ul", class_='menu') # 按照css类名完全匹配
1 P) U( w7 _1 T) o# print(tag)" {8 @& r2 E+ e! f+ w7 `5 l! X
tag = soup.find_all("ul", id='menu') # 按照css类名完全匹配7 `2 v7 n& Y0 Q: C, ^" [$ e
print(tag)
0 Z! E2 {* [7 L9 b" g0 p- t! K& c# 查找名称为a元素的标签内容
% N4 n. e3 o1 E; U9 T$ Ptaga = soup.find_all('a')
- Y- ]- L% u& S4 K7 R% l" @for tag in taga:
# _% u- I. q( \: _5 L F( f3 J% [ print("查找名称为a元素的标签内容:", tag.string)' c* a7 ]) x& I9 K& J w
# get 获取属性信息 获取整个页面的img标签图片和src属性值
E e6 m; ^6 ]! ^9 q! J; f' ftagings = soup.find_all('img')( {- b4 k9 p' K2 \7 w
print(tagings)8 c. g+ z1 a* N j* }
# 循环输出图片地址
' g8 b& ~5 F/ I g- s0 ?; ?0 ?+ Ofor imgsrc in tagings:+ @# v4 g9 ?3 I1 x4 y% |
print(url+imgsrc.get('src')). b v! g" l! q2 v& @
6 Q( O/ c5 {6 y* e; _
""""属性只能做为参数,所有的操作只能针对标签"""' |! m1 L' H5 A) `5 E6 d
; S) m5 @& P; `+ t! d$ R& y
etree方法:. B& K% e; ^8 X$ Z3 f
导入库文件:& N6 K3 m, O) N; x
* Z* S7 B! R) D5 t4 ffrom lxml import etree
+ H: l; D+ h5 y9 ?6 f1
1 {# U' P1 F' X解析得到的response对象;
4 r; Y# }- {$ Y+ J8 r7 ~: @% j, R9 K0 H& _6 l5 x
# 设置response的字符集
8 L' r9 w0 V& `9 i' {$ Lhtml = req.content.decode('utf-8')7 \2 W! `& j0 i
# 解析对象
% W+ r2 @2 X- }7 I7 I, [3 N$ [html = etree.HTML(html,parser=etree.HTMLParser(encoding='utf-8'))
8 `. H" H+ h w8 }8 [4 X) \1 m% i* ]8 Y) K8 ^3 ?8 E
常用的方法:& H: r. \5 ]( B, `! Q
9 u/ N7 E6 y/ x) ^
+ p9 M. m0 W; u( z; I4 t
# 定位head节点(元素)
* q+ a! D0 w8 U6 @) G, Sresult1 = html.xpath('head')
$ z1 ?6 b+ i, i z- w$ @print(result1)
) _' q+ B6 [) N# K9 N6 y/ M& l# 定位title节点
/ O+ \2 s# k8 [' jresult2 = html.xpath('/html/head/title')
* B) O- Y- b% i7 _9 T5 C: Gprint(result2)
# t) j" F1 _6 e% o$ m# f: c5 c# 搜索节点 title节点
! @1 n9 h! A; Kresult3 = html.xpath('//title')/ |3 A' _' u9 ~5 d0 B) c# f) q
print(result3)% W) o4 G- L$ X `3 | {
# 搜索title内容 text()得到文本信息* p7 u M$ C$ L# y7 v9 p% n+ K1 X
result4 = html.xpath("//title/text()")6 Z& C5 A/ m1 g1 o
print(result4)
9 A+ d$ X" x0 q( s# 搜索div节点
$ q. I% Y3 Q+ [result5 = html.xpath('//div')
6 x; c0 S2 i8 I, \& [( @7 W; Nprint(result5)
% L: l$ P, v& `- Q1 g' n# L, W* y# 搜索div节点 并用class属性定位
- n- ?: X- K4 O' Zresult6 = html.xpath('//div[@class="news"]')
9 @+ q, \1 E0 u. [6 ?8 R; B/ ^- xprint(result6): j' ~1 R% Q6 V z) T& T
# 搜索div节点 id属性定位. V+ a: m! p9 G' m9 B$ z3 \, w
result7 = html.xpath('//div[@id="news"]')
* q. g. K" R& Tprint(result7)3 }. u/ U$ p& T) C0 X) f3 Z$ H
# 获取列表span信息
% s* d/ R) f* I6 ]5 l, U( _1 etext = html.xpath('//div[@class="news"]/a/span/text()') S& n1 d# \- W" X+ _
print(text)
5 F, l1 u; d% D/ d4 [1 W: L: i7 K- n/ R+ I
g、通过上一步我们得到自己需要的数据后,下一步就是将我们得到的数据进行保存0 |2 \2 l) e, q" D( E" N
保存的方式有很多种:8 `- z7 y+ N# X% n+ `
1、保存至文件- c$ h% \5 ~) [
csv、json、text
. t g9 y; T4 e3 U. B2 ]% y8 d$ f2、保存至数据库$ V; e+ Y! b% T3 L
MySql、MongoDB、Redis 等 (目前主流的为以上列举的三种数据库) 关于数据存储后面再做详细介绍
) Q) _/ }. q. k; V# v
B5 Z+ f" x+ G4 i. [! V# d9 x' T, i( H/ ?
————————————————4 T! {. M4 s# R
版权声明:本文为CSDN博主「royallucky」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。( t# M- J( I8 h% `
原文链接:https://blog.csdn.net/royallucky/article/details/105930473
$ D0 b7 P: I" h5 M
; P8 j7 H5 ?7 H$ [" e. e. m5 a3 N
|