" p, U' Z1 X7 f) a: u% V8 u* @1 T; J8 b( T$ _: c# @
4 P( M7 L% q7 c7 d- e9 A! u
手把手带你5分钟搞定爬虫(聚焦爬虫) 7 m1 J' R$ ^- z& e- X9 I! h
" X; z; \& }+ i5 m2 _1 d爬虫的原理
- D( a9 y$ `2 c) K7 i& N- P! r, h7 p; y/ y: W j
对于很多刚入门的小伙伴来说,了解爬虫的工作原理是非常重要的。只有当你了解了它的原理,你才能结合实际情况写出对应的爬虫。下面我将以通俗的语言方式来介绍爬虫
% g% N9 [1 {' ^把互联网比作一张巨大的网,那爬虫就是这张网上面的一只小蜘蛛,在互联网上面有很多的数据,各种各样的数据,我们可以把这些数据比作是被网粘住的小昆虫等。爬虫的作用就是去找到自己喜欢的口味,然后把它带回家,可以储存起来,也可以马上享受美味% v3 n$ N8 n3 b8 B
所以说爬虫分为三部曲:6 i6 M, r: b k7 J
1、明确你自己喜欢什么口味(制定需求,明确你需要的数据类型)" x+ `2 q, M3 {+ g; w* m
2、去找到你喜欢的食物的位置(得到目标地址): z' Q2 y$ C2 B0 n% |
3、把食物搬回家去(解析网址,获取数据,存储数据)
2 [2 J" _& I1 h: m( L9 A+ \5 a它的整个流程就是:(简单的通过request请求获取数据并解析获取数据。以下都是固定化格式,可以照搬)+ G4 H7 y% q3 J' @8 E9 z5 `
a、导入需要的库 requests
& g4 r5 h6 j5 S% R0 T; B$ Z$ q' G1 c2 ]
import requests
, V' V* ]( k) f7 ^ ]4 \18 ]: Z) C/ i& a( i0 @) P5 b
b、明确你要获取数据的网址(这里以百度网站为例)& o. N- M" t( J% |8 x$ ?! d
. O; ?1 t9 I( Y+ A! s7 N
url = 'http://www.baidu.com'
( m4 ^. J5 b* {1
- q1 m0 [1 E% N! ^: Z lc、创建请求
% \9 t9 Q! a5 H( l
& _) {. u9 v3 f9 E# Rresponse = requests.get(url)
$ A8 k3 O! P, h0 z- Q13 m; m: b' P# h' L* }! ]
d、测试请求是否成功(在实际应用中用的比较少,正常情况都是可以请求成功的,网站对于访问外部信息的爬虫是不会做出限制的)& b# c3 _: L8 ]# }/ J0 D M
1 j3 u& q7 L/ d) Z; e
print("状态码:",response.status_code)
, G a5 v) ?% e$ H10 R. W3 X: [. p- C. J k
当状态码为“200”时表示请求成功;如果不是“200”,很大可能就是你的目标url写错了,核对一下url8 ]' z" o7 W ~6 {0 \3 `
e、得到网页源码0 c8 O5 e4 H' G5 ~6 G; T
' C& [/ E, A/ D: M% s: H: f
print("内容:",response.text)
9 @7 |8 d( J/ s1! {% |2 ]/ ~! T& w8 k6 |
response.content是response.text的二进制形式
* V. K- y3 j5 d8 z0 k
! Z, d; W1 q2 u5 [至此,一个简单的爬虫请求就算是完成了。
- J5 F$ y* s5 n" x2 }6 ]. R当我们请求目标url并获取到response后,就需要进行下一步:解析网址并获取数据
1 w7 X* m$ A5 Rf、解析网址
9 q; K8 g# K; C' [' a3 _/ v/ m刚开始学习阶段,我们最常用的两种方法,一种是BeautifulSoup,一种是etree。其中BeautifulSoup是最常用的。以下将对两种方法分别进行介绍 (以下方法均为测试用例,实际当中应结合自己的实际情况选择应用)
L- g1 F* }0 W$ V+ {2 }BeautifulSoup:
' M8 @; c/ q8 P首先导入需要的库文件:
& u" P( V& z1 N3 j, E' m6 I9 d
/ w; Z2 d( |; z" }from bs4 import BeautifulSoup
" w; ^% p6 P9 a( Y8 q1
5 d, c1 K- l8 J9 L然后对上面请求得到的response进行解析:
# P8 S# ~" A/ a- L& ~7 _
, m D9 N W, n! k6 Ahtml = respone.content.decode('utf-8')
; ~9 o, P/ n1 C& R0 Isoup = BeautifulSoup(html, 'lxml')1 ]2 R1 u4 a9 D
1
& o( H: \4 `& h( }2
' o4 M! E$ A; g8 q以下是BeautifulSoup中比较常见的方法,有兴趣的朋友可以去一一测试:
6 h3 w: ]6 C: d% w9 p# 获取head标签
. ~- l* X+ `( s% j6 Bprint('head标签内容', soup.head)
! E; q" o1 j$ ~- K" v' \4 m- Y# 获取title标签: u% `* H% u! P' F, V; |
print('head标签内容', soup.title)
: {9 T& o! _4 |5 `7 C# 获取body里面的img内容1 T* L- y2 p, x1 v
# 通过点号的方式只能获取 下属第一个标签(即获取soup下面第一个body里的第一个a标签的第一个img标签). y2 W' ~$ B" T# B1 B* O' W
print(soup.body.a.img)
$ x" b2 i7 R. g" z' L4 O# 获取所有的img标签 使用find_all()搜索整个soup对象
% E5 l! ]# g) g, }6 W8 Sprint("获取所有的img标签", soup.find_all('img'))
# u/ {1 W) m0 ^1 O# 获取标签中的属性src地址& O/ k9 o7 }! L( [) J# @5 [. I
print("获取标签中的属性src地址:", soup.img['src']) # 注意:英文点号都只能获取第一个值
' ?+ a6 t0 i# g: R" u; h
, A) [% p3 K+ ?; [+ W
$ Z, S: L4 _) ]& ?, \+ y# 获取soup的name
, L; V7 a! Q' S: eprint("获取soup的name:",soup.name)
* w2 M1 k+ y* d$ U% c# 获取a标签名- X0 G B: ^2 s; l" T7 _
print("a标签名字:",soup.a.name)
7 J \* D) Q1 ^% P, Z: t3 stag = soup.a
. N6 p. |7 s9 A9 g3 `9 sprint(tag)
3 P- k1 p. X/ V/ q$ _# ^# 修改操作 a标签改为b标签2 e w0 b& \( }5 D
tag.name = 'b' # 赋值后<a> </a>变为<b> </b>
?4 r! W+ S, r. X8 H2 r! S' T# 输出修改后的内容: L/ x4 `5 p0 C* X6 R( b
print("输出修改后的内容:",tag)6 @2 Y2 \1 r" D/ D
# 获取全部的属性 attrs
( P3 A- b& e4 x! M+ lprint("tag对象的全部属性:",tag.attrs) # 只能得到当前标签的属性(不包含下属标签)
" ?0 C0 L1 e( ?# e
6 N( ]( U! Q/ G) R+ X2 O, t# 获取属性的class的值 根据键取值! h0 g* X& {( l1 W( u# @
print("获取属性的class的值:",tag["class"])* S8 ~1 {( z9 l
* c Q5 u+ k- M F) r) c) `, Y: c& a* @8 k
" o! P3 _6 M) l
0 p3 R- B' Y% a; R1 q; W"""针对获取的标签属性可以进行增删改查"""& U! j& i( z7 d# y" Q* P9 I7 H
# 修改
! G8 h2 j' o0 l+ ?) gtag["class"] = "Logo"5 i0 c4 Y- f" d$ [, |
print("tag对象的全部属性:",tag.attrs)1 d# Z6 N3 e" }! y' @/ `, h- l
# 输出属性# w" r, t4 R( p2 w
print("获取属性的class的值:",tag["class"])
3 n. T5 ^. E6 b/ j C# 新增 属性id 赋值logo& r+ p [4 W# o1 X/ W* s ^
tag['id'] = 'logo'9 m. g; {) x8 Q9 O
print("tag对象的全部属性:",tag.attrs)
u3 A3 }, H7 { M# 删除属性. U- V1 J$ i5 P
del tag['class']: m$ O& l2 ` B0 X$ f
print("tag对象的全部属性:",tag.attrs)
* r; C% |* w+ v: l1 r* q" G
/ f' w+ O8 ?& q& W+ J
3 g& T# W0 @: j+ T; z3 W; O7 r: G8 l& x
"""针对内容操作 (只针对标签,对属性无效)"""
( m+ I4 r6 h! e! C" K# 获取title标签内容
& I! ^ \" E4 m/ C! U' P" rtag = soup.title v6 j, m; a* r! ~8 s$ l- W
# 获取title字符串
# \' l3 N8 Y* \) D$ _: C/ [print("tag对象所包含的字符串:", tag.string)
2 U9 ]& j1 [" Uprint("类型:", type(tag.string))3 ]3 x% W; x; |* @: c
# 替换内容
( u/ M* m- ]. L3 {* \6 t% ]9 dtag.string.replace_with("你好")8 M' b% N' b' d, r7 R- Y8 d. ]
print(tag.string)
0 q- E. Z* Z1 f& ^, y" N# <!-- 学科建设 -->
- b4 A5 w/ a/ P! Y2 [ S/ N. J3 n. @# 获取注释文本内容
. ~9 Q3 f7 n1 `& I. {$ |1 mmarkup = '<b><!-- 学科建设 --></c>'" }7 {# W; \. A, [3 U8 W) F' N
soup_comment = BeautifulSoup(markup, 'lxml')6 S. a4 Z) j/ \7 k( T
comment = soup_comment.b.string # 以markup第一个标签作为关键进行搜索/ m' P# B% Q; I- ]( w# E3 k# n
print("获取注释文本内容:", comment)
" M3 @6 W8 h' \ A* s% O# get_text()
& e- c3 O. \3 Q# _print("title的全部节点:",soup.find_all("title"))2 [- D4 K7 w. p; [# ~6 _7 M- q
print("title的内容:",soup.title.get_text())9 B8 _/ ~; D6 M
"""查找ul元素标签"""/ V. T; F5 Z5 f' L6 ?
# class是关键名,匹配时后面必须加下划线_
2 `+ H$ D( j+ K* k& ?& n# tag = soup.find_all("ul", class_='menu') # 按照css类名完全匹配
. N5 i f2 \" i, H9 e4 W% Z# print(tag)- l1 U {: E0 `* a/ j
tag = soup.find_all("ul", id='menu') # 按照css类名完全匹配) p7 a. R; a+ K+ t9 v% h
print(tag)
6 m$ r1 y* y5 B& T4 [# 查找名称为a元素的标签内容( i1 F# ?: O/ t; c7 x7 H7 h
taga = soup.find_all('a')& Q) y4 i! ~% m' y' I8 t+ G; |
for tag in taga:8 m# Q0 T( p- |7 {1 _: d
print("查找名称为a元素的标签内容:", tag.string)9 @& ^8 l9 ^; @8 U/ K
# get 获取属性信息 获取整个页面的img标签图片和src属性值 r0 _/ F: ~3 I
tagings = soup.find_all('img')6 Q) p* @* j$ S% z7 q
print(tagings); n) i& S* d" ~* ?: B! E, j
# 循环输出图片地址0 R+ O0 S& I" t% [
for imgsrc in tagings:- h& G3 s N3 a8 O1 w; {6 \1 A: c! L
print(url+imgsrc.get('src'))
. C7 W3 P3 \6 _9 C& i
2 m2 W3 b8 h$ x- Y. v""""属性只能做为参数,所有的操作只能针对标签"""
9 @) y3 ]% O2 }" w( a7 T: e$ e2 @% b# i& H
etree方法:' O2 G! f( P) n0 i. f$ X) E
导入库文件:- v8 @. J/ ^8 M
5 l' w: \/ @" [0 [
from lxml import etree
% j# S4 W5 [+ @& t. \$ J4 Q1
# I8 Z7 _1 b0 P解析得到的response对象;7 p: f& o( x C# q0 L" u
4 V* Z8 u, F/ X8 C# 设置response的字符集4 L8 P8 Z5 s- C$ n# O L
html = req.content.decode('utf-8')
4 D4 f3 M. _+ G# 解析对象* k9 o' G5 m( a2 p, K, x5 v3 S. ^
html = etree.HTML(html,parser=etree.HTMLParser(encoding='utf-8'))! M& `/ N: q4 A6 `. o# Z
' D, M9 k5 p& m8 }: s
常用的方法:
; x% D4 Z @4 D
1 G8 }2 B5 {7 O( g) N; L" Z. S, U# t$ H: m0 |0 Q4 h: [; O
# 定位head节点(元素), D9 W5 ?" r8 q( i* |' Q- p8 k
result1 = html.xpath('head')( s) e7 m1 J) ?0 _
print(result1)
9 {! l, N, i7 |. I& d# 定位title节点
! l7 p8 i4 L( Eresult2 = html.xpath('/html/head/title')
# W1 Z9 P: Z7 y2 x; bprint(result2)5 \$ t0 y+ }) j( z0 u
# 搜索节点 title节点) J' g$ e; f9 |4 q+ A, v
result3 = html.xpath('//title')7 m+ T4 v! ~# J* ^3 N+ |% }5 {
print(result3)& S. L0 `, ?- @ J' I f$ ?# F/ P0 p/ [
# 搜索title内容 text()得到文本信息: ], c4 M5 C3 i4 F: y) g L
result4 = html.xpath("//title/text()"); @- h- [6 | A/ B
print(result4)
( g" I' m/ i! W7 G0 I" F. N# 搜索div节点" M: n2 b5 r3 W% n: d
result5 = html.xpath('//div')
; y/ l9 R, i: g8 M+ T8 b6 l, fprint(result5)
0 _. S- ]3 _% b( g# w E# 搜索div节点 并用class属性定位* c" U" Q+ h* g& J" C& N
result6 = html.xpath('//div[@class="news"]')
8 B$ z' R: r$ P0 K4 Yprint(result6); u" {' ?7 U7 {# c( E0 ?- Q
# 搜索div节点 id属性定位
% S: }1 V; Z! c# I. L! C% v: `result7 = html.xpath('//div[@id="news"]')
6 o7 r O; f: _( `5 c: |print(result7)7 B$ q `! y6 U" v% |+ y
# 获取列表span信息$ `! M" P; n1 w+ G3 O" O) z
text = html.xpath('//div[@class="news"]/a/span/text()')
- V; Y. y9 U: zprint(text)
; o8 n, |/ ^9 u2 l
, Y4 ?- _1 O* h. O- _. ig、通过上一步我们得到自己需要的数据后,下一步就是将我们得到的数据进行保存
, T3 ?# Z; e; M3 B& h保存的方式有很多种:+ `- C/ l- w2 n- ]9 q2 \0 h$ L
1、保存至文件
7 Z! }0 B+ _8 M, _6 Y% `2 H7 {csv、json、text
3 c% v& v) [* x- \2 I# R5 @2、保存至数据库) t' E$ }4 m0 z
MySql、MongoDB、Redis 等 (目前主流的为以上列举的三种数据库) 关于数据存储后面再做详细介绍$ n: D, n2 d5 X9 j4 G
1 k: [! F4 O& y% l( j3 t$ s6 e E0 n5 Y
4 z s+ W6 Q# E+ q
————————————————- ?. h# z7 b7 Z( L4 K- U$ ~. c
版权声明:本文为CSDN博主「royallucky」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
7 N3 @0 b/ H$ f Q! i( j, G$ M+ v原文链接:https://blog.csdn.net/royallucky/article/details/1059304733 [$ Y) @9 k$ w" g
. K2 d S- J) i
0 Y( i. t, t: O; n' q( y4 v" x |