' z% b: j3 A4 y! d4 V2 }
' Z2 u, B4 B/ J' d+ E5 c" `
6 f/ i* R& e: v; g手把手带你5分钟搞定爬虫(聚焦爬虫) 7 s+ F. f% `8 o5 ]7 {. A4 n
* S% m9 J8 k' ^9 F& Y, a5 s' \) z爬虫的原理' J2 D4 o1 D3 ?6 d! p: ] W' Q
- @, {4 y5 N8 S% j对于很多刚入门的小伙伴来说,了解爬虫的工作原理是非常重要的。只有当你了解了它的原理,你才能结合实际情况写出对应的爬虫。下面我将以通俗的语言方式来介绍爬虫
+ \$ d8 u1 D! y9 `& W把互联网比作一张巨大的网,那爬虫就是这张网上面的一只小蜘蛛,在互联网上面有很多的数据,各种各样的数据,我们可以把这些数据比作是被网粘住的小昆虫等。爬虫的作用就是去找到自己喜欢的口味,然后把它带回家,可以储存起来,也可以马上享受美味
- U8 Y, p7 p% h所以说爬虫分为三部曲:/ N% v9 M( @; d* x1 U
1、明确你自己喜欢什么口味(制定需求,明确你需要的数据类型)+ A% J" m& F* I; |5 P
2、去找到你喜欢的食物的位置(得到目标地址)) J$ t. E5 m& w/ ~8 J, K# k& n4 s9 r
3、把食物搬回家去(解析网址,获取数据,存储数据)* `4 |9 L# }+ ~4 S9 ]" r
它的整个流程就是:(简单的通过request请求获取数据并解析获取数据。以下都是固定化格式,可以照搬)
! `: k. \! x+ ^, g, d8 ]a、导入需要的库 requests
( {7 R. f3 N0 s
9 ?% }; o, @- F. fimport requests- v1 X3 v, r1 T, j! p% ?4 F# a
1
/ ?3 \9 f$ C2 |4 e$ {8 ~8 J/ Ab、明确你要获取数据的网址(这里以百度网站为例)% a+ s# |7 Y# U3 f7 e& s
4 B; \& L/ t/ G4 P1 Z& D5 B0 c; O; n
url = 'http://www.baidu.com'6 i5 P3 P& q% y" g0 |
1, Z; R( V* B' j: F' i; P. G( `
c、创建请求. _' M w1 ~' n/ |
6 t' @" y: b; i8 K1 O& A4 U1 [- d4 M7 xresponse = requests.get(url)
9 R; v Q% U, `$ G9 ~1
' @/ \; `, k# u* Td、测试请求是否成功(在实际应用中用的比较少,正常情况都是可以请求成功的,网站对于访问外部信息的爬虫是不会做出限制的)
. h4 D+ G9 |4 k) T+ @( J1 f
7 B2 K. v/ s+ o' O$ ^( h& tprint("状态码:",response.status_code)
4 ~4 ~* M( i* P1
5 T1 ]+ _# `3 u4 G: r6 R% C+ k2 s当状态码为“200”时表示请求成功;如果不是“200”,很大可能就是你的目标url写错了,核对一下url
4 L, \7 A% K9 Y o7 }# H& z, le、得到网页源码
8 h! H" D, }; C8 k: o5 u, n# G, Z" m! W t0 {. G
print("内容:",response.text)
7 p- d! k9 E" Y9 O( X1 T, ?. Z& S- [- u: F
response.content是response.text的二进制形式
* p5 @7 o$ S0 W: ^) r6 T8 F
; @# q" h5 |+ O. Z. |! M5 v至此,一个简单的爬虫请求就算是完成了。 O# T( d' ]5 T6 M0 E1 X8 L
当我们请求目标url并获取到response后,就需要进行下一步:解析网址并获取数据- ^' F* {2 b% \& i, A
f、解析网址
3 T6 A) Q9 a' m' ]刚开始学习阶段,我们最常用的两种方法,一种是BeautifulSoup,一种是etree。其中BeautifulSoup是最常用的。以下将对两种方法分别进行介绍 (以下方法均为测试用例,实际当中应结合自己的实际情况选择应用)
. Q3 {, d: @9 }& u/ @0 o! K2 ?BeautifulSoup:3 q/ ^5 ]7 S! ~. r( [7 q- X( b
首先导入需要的库文件:% Y5 W( X4 X* |; g/ F. i
9 w/ D' @3 p: C# j" U. }from bs4 import BeautifulSoup
; s& Y# [' ]1 [: @5 ^9 m3 ^; K: u1
+ `4 j* b" E- y5 D! C) G2 u然后对上面请求得到的response进行解析:
: R- R% e+ a0 P$ o3 F" H& ~
- d' N9 T$ _( _* j3 @. f# zhtml = respone.content.decode('utf-8')* k+ z+ V5 q# S* i/ h
soup = BeautifulSoup(html, 'lxml')1 Y& }$ x" r+ ?! `: k# r
1$ m8 E9 T L+ }0 l- v) e* U0 `. e
2
~6 n& l( i" ]5 {! l- }+ G# s$ u以下是BeautifulSoup中比较常见的方法,有兴趣的朋友可以去一一测试:& Z( q* w, I* {
# 获取head标签
; H$ R( w! h0 q* w- }( Mprint('head标签内容', soup.head)
$ [' ?5 g( j: N* g- k# 获取title标签
9 D& Z3 z6 j3 Q: Z8 uprint('head标签内容', soup.title)' w2 ?0 n( {+ q, g8 f9 R* s
# 获取body里面的img内容; o$ r" P3 @" ~* r
# 通过点号的方式只能获取 下属第一个标签(即获取soup下面第一个body里的第一个a标签的第一个img标签)5 e" d) a* y7 y& [0 E" k- S
print(soup.body.a.img)
9 _% k) @* B$ ~# M# 获取所有的img标签 使用find_all()搜索整个soup对象
, }' |% J. }4 X- Y7 I6 Q+ N2 I* x' Yprint("获取所有的img标签", soup.find_all('img'))
& X* Z: @( Q- F0 }$ Q$ {# 获取标签中的属性src地址! r3 Y, Z4 R B/ ^8 y
print("获取标签中的属性src地址:", soup.img['src']) # 注意:英文点号都只能获取第一个值
; b/ [2 X/ r3 f, `6 T& C B) {& Q* ]
! T& ?" U' a& G$ P# 获取soup的name5 k& p$ t+ h- F+ w$ F+ o
print("获取soup的name:",soup.name)5 Q" V6 D* W9 Z- m) c
# 获取a标签名5 H |7 U1 B7 k# o
print("a标签名字:",soup.a.name)
/ z9 v, B& f F: q7 {2 p: w8 ytag = soup.a4 l; Y# w# l6 F: v. G
print(tag)9 L$ s. w0 ~/ b4 B4 K3 a
# 修改操作 a标签改为b标签
0 v* i# d3 S# x7 ~+ ^tag.name = 'b' # 赋值后<a> </a>变为<b> </b>$ ?7 I% ?4 f$ ~$ D3 S
# 输出修改后的内容# K; O& ~ `" h7 ~. X0 E
print("输出修改后的内容:",tag)
, ~* ]9 Z! T6 y& x& C! u2 w# 获取全部的属性 attrs
1 B; U) w, l8 ]0 y' t: a' ^/ Eprint("tag对象的全部属性:",tag.attrs) # 只能得到当前标签的属性(不包含下属标签)
3 K/ M) m% R7 x0 L/ P5 Q# h# n/ u% O/ v2 G8 |& b5 a* i, d' N- w
# 获取属性的class的值 根据键取值
" u) l @6 [1 ?9 Z& K. G9 s0 zprint("获取属性的class的值:",tag["class"])
$ n8 n3 r3 U4 R4 W* r
( e# ]3 s l* {, u, D" \ s0 p+ H9 ^5 P/ A, Q, O" F3 L
* G u& _$ Q; j7 q/ S0 v* Q* T' N5 c8 Q; u' A, f$ L3 r: g9 F8 n
"""针对获取的标签属性可以进行增删改查"""3 q" K9 E$ v$ B3 q0 _# k/ U! a) X
# 修改- H/ j$ c6 J9 b# q$ A
tag["class"] = "Logo"
& k- _9 N( [: o; h! ?1 lprint("tag对象的全部属性:",tag.attrs)5 p7 i& P4 K* S. _: T
# 输出属性, D! v8 [( q/ n ]: M/ t
print("获取属性的class的值:",tag["class"])
g6 v, \7 V# p6 D# 新增 属性id 赋值logo
2 S$ Y2 P( n5 T4 t$ R- utag['id'] = 'logo'8 B' K3 N* Q- e1 F
print("tag对象的全部属性:",tag.attrs)
- _! h/ j3 @$ g( j/ [3 Z0 Z& d# 删除属性
, u, C& c+ S# W5 ]2 n' [del tag['class']
3 F0 U7 d/ [* E# Lprint("tag对象的全部属性:",tag.attrs)% k1 M4 a, ~2 M2 f8 t, m
3 c0 e* n5 Y' a; A4 J
' ?% @: W, q, F0 [) g4 r" s. p* h
' e( x4 \( r) r8 u. T# t( _! m"""针对内容操作 (只针对标签,对属性无效)"""
+ O, |$ z8 p, Q4 T& m# 获取title标签内容
2 D; D3 N; H+ j% mtag = soup.title
) u9 L! ~# \9 g: ]" s# Z# 获取title字符串
: I: Q k* L! q( [9 _* s% {print("tag对象所包含的字符串:", tag.string)( o/ |3 H# D1 f! T
print("类型:", type(tag.string))9 u2 Z0 n6 a! {( E
# 替换内容( X6 n+ [; b3 M) v/ n
tag.string.replace_with("你好") g" Z# z6 O/ d9 e: b ^
print(tag.string)5 {5 N8 g* j& r: k+ E
# <!-- 学科建设 -->( Y! a) I6 [2 j# g( ]
# 获取注释文本内容
* }% I& D0 E6 Vmarkup = '<b><!-- 学科建设 --></c>'8 ]- x& l/ k, P8 o
soup_comment = BeautifulSoup(markup, 'lxml')
# [3 P6 g; C- ~! e% Y) jcomment = soup_comment.b.string # 以markup第一个标签作为关键进行搜索
1 G+ S' u1 \+ X! M% P/ L/ o" fprint("获取注释文本内容:", comment)
+ I( k. c" l3 J; Q- c1 d6 I# get_text()
4 Y6 y3 l# i4 A+ W! ]. iprint("title的全部节点:",soup.find_all("title"))- s. u2 e/ ]5 v" a: d V5 u: R
print("title的内容:",soup.title.get_text())
' u1 \% [* H. W6 o- g"""查找ul元素标签"""
3 c$ E( I6 S7 S7 G) O# class是关键名,匹配时后面必须加下划线_
) Z" R1 \' t$ z; A; v# tag = soup.find_all("ul", class_='menu') # 按照css类名完全匹配' ^7 r0 [ i6 X/ }% L" F
# print(tag)) l2 {* @& ]$ { G& s- W
tag = soup.find_all("ul", id='menu') # 按照css类名完全匹配' {6 r$ d0 d5 W6 {% Y: l
print(tag)# P& \. [* r1 k/ m
# 查找名称为a元素的标签内容7 `5 H! |& q' l$ A
taga = soup.find_all('a')' T, y- q1 O4 }1 q, q3 [
for tag in taga:$ p) G9 i8 C- a$ K" e
print("查找名称为a元素的标签内容:", tag.string)$ v* m1 B. {1 e4 C: @( n- F |0 a
# get 获取属性信息 获取整个页面的img标签图片和src属性值
8 W$ k- |2 ~9 Z( D ttagings = soup.find_all('img'): C! q" j9 M- ]& o* w( B1 i8 l
print(tagings)' _ X& V4 h/ R7 a) s
# 循环输出图片地址
# r2 V6 n% P3 W7 d! x" m( [for imgsrc in tagings:( N+ n0 \9 Y: Q( E, C
print(url+imgsrc.get('src'))" \! H+ D2 V) M' f; A
$ `) s5 o6 D7 W3 p( u
""""属性只能做为参数,所有的操作只能针对标签"""- o! x2 Z# M& o2 r& n, n
8 G1 u( D) a$ R6 b+ i" a7 r7 yetree方法:
, t% N7 L& L1 p( F2 i导入库文件:
5 x) ]$ Y; j' g/ O9 _ L( W4 H; D5 m+ n
from lxml import etree# W9 G' x: F; @: [. B `* X1 j
1
, i' M) N% p! } Q, v解析得到的response对象;
|( \2 ]% s$ ~& H3 b" f: x( T& U% N5 b' ]" ^! x* t) w
# 设置response的字符集0 |6 H$ w0 {3 M# q* C6 ?
html = req.content.decode('utf-8')% I e7 H M" B0 [* R" _! H
# 解析对象5 t5 ^# ~& h, H
html = etree.HTML(html,parser=etree.HTMLParser(encoding='utf-8'))7 t# z3 C: e5 @/ g
2 G- s2 q3 _ Z. R8 X
常用的方法:8 K& O2 t9 c* d9 _
& x2 U r- j# v: n
1 d) [7 p0 X+ w2 e& Z# 定位head节点(元素)! Y/ ?: U/ y6 g( Q1 |
result1 = html.xpath('head')/ u# D6 w. O) e
print(result1)
3 m+ ]5 c( s3 S$ t+ `# X# 定位title节点# j5 o* n( [' \
result2 = html.xpath('/html/head/title')8 c0 m+ d; v" @$ [" n$ P |
print(result2)
2 ]% B6 m* l. C& s7 {. Y# 搜索节点 title节点
1 ~0 p0 {/ G/ E. V [result3 = html.xpath('//title')
2 m' k3 g/ i0 ?print(result3)
! `+ r1 e8 E' `) Q6 A6 x# 搜索title内容 text()得到文本信息
8 e7 s. ^: T. k0 U, i9 x4 \1 N4 v9 sresult4 = html.xpath("//title/text()")( O: S% f- V; x2 r8 K
print(result4). s1 b1 e* h5 X2 @& x, |
# 搜索div节点+ ~: h) F' B l9 s1 G+ _1 D
result5 = html.xpath('//div')
$ Q. K1 {4 M7 y8 v' b) p' Gprint(result5)
8 ?+ n; m* c5 s/ Q8 E- `# 搜索div节点 并用class属性定位
0 {6 M: e: G2 g7 q1 V0 w1 Dresult6 = html.xpath('//div[@class="news"]')* z% n3 `( m5 v- r$ ^" I! k0 g
print(result6)' v7 z. T: G& R
# 搜索div节点 id属性定位
" N3 U- N2 F3 l9 s, i$ ~result7 = html.xpath('//div[@id="news"]')
9 e! T. z- L+ x7 K0 c& m, I- u" Lprint(result7)
T% T& f" m; Y( Z% X! F# 获取列表span信息5 s* F; ]" p+ G5 C
text = html.xpath('//div[@class="news"]/a/span/text()')2 C% b& E6 g. w: b2 X
print(text)% e/ f/ }% j7 C& |' R- y( q
7 z6 l) K2 M" V; x4 v) Z6 Z9 j' E
g、通过上一步我们得到自己需要的数据后,下一步就是将我们得到的数据进行保存6 }$ u& K% K \% c
保存的方式有很多种:4 d# }8 U/ h) a& F7 \
1、保存至文件
a- W3 O. z! G: E7 W8 gcsv、json、text/ e0 v8 X! t% A* U8 V
2、保存至数据库$ J4 Y& H% [8 W+ |' x& z/ q8 @% x
MySql、MongoDB、Redis 等 (目前主流的为以上列举的三种数据库) 关于数据存储后面再做详细介绍# M) E2 O) h& Y* d# t) Z/ [0 x8 D
& }6 o3 R' C1 G6 T, b
+ a" `* [7 w( x: U& G0 m( C————————————————6 ]3 C; u6 d. _" N
版权声明:本文为CSDN博主「royallucky」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
2 S# R0 N* r' g+ l/ R5 d, ?原文链接:https://blog.csdn.net/royallucky/article/details/1059304732 i% {8 K; @. i
- f" W7 C0 U0 o! @: D* Q7 o8 y7 G0 T/ r# `! f
|