* J h* q# i# w- b. h
- Z- a: J6 P& M* q# u" I3 c. m
( g8 Y9 W& [1 V0 R* c$ V' l( e- J手把手带你5分钟搞定爬虫(聚焦爬虫)
M( m+ X. A/ ?5 s; n8 W, Y4 W% T% x2 g- w: U8 C7 y0 G# ?9 F
爬虫的原理2 f' F* S# v. k) l2 ?9 ?0 Z- q
" _# Q4 g8 [2 j对于很多刚入门的小伙伴来说,了解爬虫的工作原理是非常重要的。只有当你了解了它的原理,你才能结合实际情况写出对应的爬虫。下面我将以通俗的语言方式来介绍爬虫; B$ L1 x+ P5 S' `' d6 n
把互联网比作一张巨大的网,那爬虫就是这张网上面的一只小蜘蛛,在互联网上面有很多的数据,各种各样的数据,我们可以把这些数据比作是被网粘住的小昆虫等。爬虫的作用就是去找到自己喜欢的口味,然后把它带回家,可以储存起来,也可以马上享受美味4 R0 o- o9 u& f" P( O
所以说爬虫分为三部曲:: F7 j8 Q, A- m0 e4 K+ {! w
1、明确你自己喜欢什么口味(制定需求,明确你需要的数据类型)
+ l6 L( Y: F8 ~2、去找到你喜欢的食物的位置(得到目标地址)5 O6 Y3 W1 S6 L" v A
3、把食物搬回家去(解析网址,获取数据,存储数据)
: h+ ?+ Y7 c8 r% q3 Z/ a& n, T4 ?它的整个流程就是:(简单的通过request请求获取数据并解析获取数据。以下都是固定化格式,可以照搬)' P/ ~8 W2 m7 { h
a、导入需要的库 requests1 o2 ~: @, [% v* Z; I# c* P
) f0 L- j A" V$ r! x6 iimport requests3 a- w/ m. {, C. I( o' [' j, {" G
10 G7 F6 b$ E; L: ?4 v
b、明确你要获取数据的网址(这里以百度网站为例)
8 g! ?8 F4 O0 t7 \2 ] N a3 h( u* c1 J/ @+ B% s
url = 'http://www.baidu.com' }4 Y6 x/ j9 S) R
1* V; R6 ~# r; c1 D$ B' `, ?
c、创建请求
3 b: r8 \) }+ o
! l/ `1 w- @' f) J3 F0 eresponse = requests.get(url)5 X* `9 W1 _% q: ?0 e2 e8 n/ I
1% g* v" V" u% Y$ o# x$ u6 l
d、测试请求是否成功(在实际应用中用的比较少,正常情况都是可以请求成功的,网站对于访问外部信息的爬虫是不会做出限制的)4 ?8 }$ a2 D4 r% }, x2 n" R
2 P* v2 d7 i& D9 ^print("状态码:",response.status_code)3 s3 m$ E) U& P( A
1
4 c: y, t1 b( z当状态码为“200”时表示请求成功;如果不是“200”,很大可能就是你的目标url写错了,核对一下url1 @" m; h4 \6 B! N" g' a
e、得到网页源码( F6 I- P& {+ d
1 k' r& I* n4 }/ ]
print("内容:",response.text)7 P# A1 g9 }5 u
1; C- X; Z* S; U
response.content是response.text的二进制形式" O/ n6 O3 {& y1 \
9 {. \% g6 w6 q+ |/ r# c4 M5 T
至此,一个简单的爬虫请求就算是完成了。
3 d( U( Q9 V5 V" M3 o当我们请求目标url并获取到response后,就需要进行下一步:解析网址并获取数据, _& X- U4 D8 H9 ~0 D
f、解析网址
1 l8 E. Y7 F* W" o6 @9 i刚开始学习阶段,我们最常用的两种方法,一种是BeautifulSoup,一种是etree。其中BeautifulSoup是最常用的。以下将对两种方法分别进行介绍 (以下方法均为测试用例,实际当中应结合自己的实际情况选择应用)
' j8 D6 ~7 t( r3 Z- e. XBeautifulSoup:# ~% D* ?" _" s
首先导入需要的库文件:4 ]! \: B8 O3 ?
. C# ^4 M+ \8 V
from bs4 import BeautifulSoup
' M: D$ R" V. P# ?1 a11 B0 I" U9 b9 l/ {# u8 ]( }; f) u: l
然后对上面请求得到的response进行解析:
# D- l8 ~4 a( J6 O" M+ Y+ k" U1 X. M" p. C p3 b4 p; N
html = respone.content.decode('utf-8')$ V+ o. _+ M* Q% A" H
soup = BeautifulSoup(html, 'lxml')+ d4 ]7 d7 D6 u8 H* Z. h
1! [* g7 [+ o6 u& n) g) k: |4 K
2
0 t# t0 M1 v" y+ l8 Y) i( r以下是BeautifulSoup中比较常见的方法,有兴趣的朋友可以去一一测试:! O$ `- |+ o5 N1 J5 |3 R3 K
# 获取head标签- \/ q3 c; m4 @ X2 I
print('head标签内容', soup.head)3 L4 ~" ^% {+ c+ S9 }
# 获取title标签 k* a: x A5 |1 H) P7 R" j
print('head标签内容', soup.title), ?0 |" s# l% D# Z/ T6 f3 g
# 获取body里面的img内容 ]3 K; d5 S1 D9 [
# 通过点号的方式只能获取 下属第一个标签(即获取soup下面第一个body里的第一个a标签的第一个img标签)
; m2 T# j b2 `% \7 J* c2 Y( {print(soup.body.a.img) 2 }! D& p& a" b. C- m/ B& P' T
# 获取所有的img标签 使用find_all()搜索整个soup对象$ z; x+ Q+ r7 s6 z
print("获取所有的img标签", soup.find_all('img'))
/ H. x5 X) K2 D# 获取标签中的属性src地址
" B$ y/ H. q) k; @6 i6 nprint("获取标签中的属性src地址:", soup.img['src']) # 注意:英文点号都只能获取第一个值: s A3 m( H+ ?# s: d( O% `
. g( j3 N) f% p9 p' H, q$ F; t
) F7 _+ S6 E; P) V# H. U5 S
# 获取soup的name7 W# u4 N* F# A( c2 I! D6 y
print("获取soup的name:",soup.name)
# o- H8 {' b( K; f: p: {; U# 获取a标签名0 n/ n9 ]. U8 R! V4 C8 l: w
print("a标签名字:",soup.a.name)- _5 ?( E% u0 h( e/ f3 _
tag = soup.a
8 H! {' @8 S$ _print(tag)
" p2 c U; ?: S. U# `3 n# 修改操作 a标签改为b标签
! ]* a0 D I* }# s( ^, Utag.name = 'b' # 赋值后<a> </a>变为<b> </b>1 Y" ^( Z' K8 \: s
# 输出修改后的内容
* O \( a! o o6 L, G8 m& vprint("输出修改后的内容:",tag)
" u5 a Q1 t. h$ j/ k7 Y# 获取全部的属性 attrs$ H3 F: W" W! r2 i* S' S' d7 x
print("tag对象的全部属性:",tag.attrs) # 只能得到当前标签的属性(不包含下属标签)0 o: n( M3 ]) Y- |8 a( ~5 ~: X
) ^1 i/ Z3 R+ ~6 |" v
# 获取属性的class的值 根据键取值
+ J& Q) c9 y6 f. E' ]print("获取属性的class的值:",tag["class"])
2 F1 y' }( L" k9 f1 w$ @+ |3 [9 j1 R) v w
9 i" a$ ~& j3 C
4 Q. ?% F5 X8 l8 u: {7 x
8 G, Z, N- O2 V
"""针对获取的标签属性可以进行增删改查"""- Z- i8 T) |* b, C( m; h$ e% q
# 修改/ b& m4 K* e+ W( [, Q* v/ r
tag["class"] = "Logo"0 ` a4 s' H7 q; R% {6 y, U
print("tag对象的全部属性:",tag.attrs)
& T7 w3 X8 m7 P3 x* n# 输出属性) P9 k& T* s" y
print("获取属性的class的值:",tag["class"])( q, a3 p3 H' ?* _% A* L
# 新增 属性id 赋值logo; l' C$ q/ A8 ]- v' I' D' y
tag['id'] = 'logo'
0 Y. i9 y# k- z4 ?+ d" E& u8 iprint("tag对象的全部属性:",tag.attrs). n! y; [: Q# A- U
# 删除属性
D( a" l8 [2 h3 J2 Sdel tag['class']
9 [5 d# t% T5 v+ S- Dprint("tag对象的全部属性:",tag.attrs)6 ]. ^2 R6 ~4 _" \3 n( B
5 e$ L9 ^/ j; o% O* n0 F& A* H! S$ t% ~, _4 k1 n' Z+ S
( q. k; M+ o. `+ W: Y9 ["""针对内容操作 (只针对标签,对属性无效)"""
3 e( Y d( e* q2 {7 g# 获取title标签内容
7 X4 j t7 ]5 |$ X" V" F6 x$ K! @tag = soup.title
- B' |% i6 `6 \# 获取title字符串
# ?, x F5 H% f. T6 \print("tag对象所包含的字符串:", tag.string)
2 Y3 t. O3 h. _# \print("类型:", type(tag.string))
, i9 @+ I: }7 ?$ [0 f$ g# 替换内容
' b' u' F/ z/ ctag.string.replace_with("你好")
/ g( j0 w! g: P2 Jprint(tag.string)
* V6 F$ r1 ~7 a# <!-- 学科建设 -->8 t$ Q; J6 N/ Q
# 获取注释文本内容: ~* V; H& t3 X' P6 [
markup = '<b><!-- 学科建设 --></c>'
& c Y. ]5 x, V/ j/ `/ z" d) p; fsoup_comment = BeautifulSoup(markup, 'lxml'): V$ U- Z+ }* d
comment = soup_comment.b.string # 以markup第一个标签作为关键进行搜索 j/ S1 V& c: f9 V. V2 ^
print("获取注释文本内容:", comment)* v; t+ U- S, I' s, H' X/ O
# get_text()' j" X4 L* M' u1 t4 v4 [
print("title的全部节点:",soup.find_all("title"))/ X8 O# K1 Y U5 `
print("title的内容:",soup.title.get_text())
5 r5 I9 I1 N! H"""查找ul元素标签"""- Y8 _; I* J- d N
# class是关键名,匹配时后面必须加下划线_) \+ U* v$ }, J# T* f1 q
# tag = soup.find_all("ul", class_='menu') # 按照css类名完全匹配
6 B2 K: I, }0 ~; c2 Q; b# print(tag)$ q \6 }4 X: a1 w0 W5 t% ]( e: {$ R# n
tag = soup.find_all("ul", id='menu') # 按照css类名完全匹配0 t2 U, y3 x: |; v9 M9 b; `( D
print(tag)2 ~! C4 X: V" ]2 } r8 F( a, n
# 查找名称为a元素的标签内容
, ]' x8 V; G, @* j- d6 ytaga = soup.find_all('a')" l& U# M% c$ B3 [
for tag in taga:" A" q/ a7 n4 X# y
print("查找名称为a元素的标签内容:", tag.string)& H/ t! @! I' v/ z
# get 获取属性信息 获取整个页面的img标签图片和src属性值. c8 v- G& Z) S" T
tagings = soup.find_all('img'). t) m7 }3 q- u) n
print(tagings)5 K6 g! n, ^8 I
# 循环输出图片地址8 F- t: G5 X) u- q: S/ z
for imgsrc in tagings:" r) X5 ]% j% k$ \0 @' @& R! |
print(url+imgsrc.get('src'))
1 p( @. h8 r: I$ K4 i
, a2 |. r9 Z c9 m""""属性只能做为参数,所有的操作只能针对标签"""- b- ~8 O/ _0 Z
! R5 X( A; ?9 Z2 v4 \
etree方法:
5 Q, q0 v8 e/ g导入库文件:
8 E3 u8 H W; I/ F# K9 w# N' w# m" ?9 j: _4 [! N% m
from lxml import etree3 A! r# Y6 f2 I8 Y" e( m
1
3 N/ b0 Z( C* w* W7 G9 B' k0 y解析得到的response对象;
; H. e, L* N( @$ A% Y& O
! M7 e, O6 u. b1 M# P# 设置response的字符集/ M( m! o7 r# C; W7 X4 O
html = req.content.decode('utf-8')+ u; A/ P0 m/ g; N- F; [0 E9 K
# 解析对象
4 v: Z. x- [" d) S1 rhtml = etree.HTML(html,parser=etree.HTMLParser(encoding='utf-8'))& s% |$ l8 M9 q/ `( ?. v
. s* T! V' ?$ N
常用的方法:, W3 q9 E+ s) Q, l
+ E, N- ~' _6 b5 `
2 Y+ h2 k# @+ t1 y& t+ O @# 定位head节点(元素)
+ N, y( K# d8 R: Iresult1 = html.xpath('head')
9 D- {) @. w) z" F* t6 J1 l8 Y3 Yprint(result1)% f/ f8 e( F) i* b5 p6 `% G g3 F
# 定位title节点: I( T, r, i2 m, u- o$ a# o
result2 = html.xpath('/html/head/title')
8 |7 L% ]8 a5 p) C: zprint(result2)
5 j$ P6 z& ~7 S; [9 G# 搜索节点 title节点
2 V( `, }+ [7 d7 d- w+ x/ fresult3 = html.xpath('//title')) _, e' h+ b* T D3 ]1 o+ z
print(result3)6 { x7 }- c$ l" O3 b, j4 n; u
# 搜索title内容 text()得到文本信息
1 s* l8 w. R+ |% [& j" b8 I2 fresult4 = html.xpath("//title/text()")7 Z& ?: f5 _5 u9 m0 X0 q% `% r/ a
print(result4)
' m1 u' S0 N- r& C! E# 搜索div节点' V) Z/ i' H& V3 [3 M
result5 = html.xpath('//div')! }5 M/ O X- H, O
print(result5)
. d2 u! A' N3 b" n! M j- n9 M# 搜索div节点 并用class属性定位" O2 o4 D4 ^2 A% U! s. d, Y, s, Y
result6 = html.xpath('//div[@class="news"]')) V4 i3 [) r( g/ K
print(result6)
5 @0 P3 K1 y/ o! ?( A9 k# 搜索div节点 id属性定位
* b1 Y5 G2 G* f% b; E# Rresult7 = html.xpath('//div[@id="news"]')
# }# k/ J/ x: }( ?print(result7)- A9 P$ U4 q/ R( O+ V+ \
# 获取列表span信息! b, {$ `! A w6 h
text = html.xpath('//div[@class="news"]/a/span/text()')
# N, i1 N, a1 u* g- E lprint(text)
* ]2 ]& k- e/ w. q5 d1 L
7 X8 P( u+ R$ q' c; l2 X! D3 ~g、通过上一步我们得到自己需要的数据后,下一步就是将我们得到的数据进行保存
{. r' M# t. D) _/ y( ^% _! M保存的方式有很多种:
7 {0 ~3 p" K) R& k4 l J7 r1、保存至文件
" v5 ]! ^5 v+ f8 ]6 @+ Qcsv、json、text
# Y* g1 k+ A: T; y% [6 v+ x2、保存至数据库+ g) I, N, [6 C8 M9 z
MySql、MongoDB、Redis 等 (目前主流的为以上列举的三种数据库) 关于数据存储后面再做详细介绍 X8 w+ Z1 m9 p3 r
7 V5 H" C: b( k% |* ^+ q9 R
8 G/ b/ R: h! i9 I————————————————
! G, z1 s8 \$ [3 c版权声明:本文为CSDN博主「royallucky」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。. Q- D9 H1 W$ h
原文链接:https://blog.csdn.net/royallucky/article/details/1059304730 c/ D; g8 ^/ e6 s! U6 `0 }0 U
8 U4 s1 a% O* w
4 ~/ ?0 r$ _# f" M/ H, r" @% J |