数学建模社区-数学中国
标题: 手把手带你5分钟搞定爬虫(聚焦爬虫) [打印本页]
作者: 杨利霞 时间: 2020-5-5 14:21
标题: 手把手带你5分钟搞定爬虫(聚焦爬虫)
4 _. e: S X$ ]- T) `5 q6 m" u
0 K' I3 N2 F- p4 W
- \8 k5 [5 z5 q8 x手把手带你5分钟搞定爬虫(聚焦爬虫)
2 n' V, p) v3 J, ~% X! s4 E( f$ {3 u$ e7 j, B
爬虫的原理8 B' f) X( X* Z; Y" P5 o# Q3 g1 @: S
# O0 Y2 f) c$ U7 F$ a6 j4 Y对于很多刚入门的小伙伴来说,了解爬虫的工作原理是非常重要的。只有当你了解了它的原理,你才能结合实际情况写出对应的爬虫。下面我将以通俗的语言方式来介绍爬虫
3 z( o) P& v6 A/ e! G把互联网比作一张巨大的网,那爬虫就是这张网上面的一只小蜘蛛,在互联网上面有很多的数据,各种各样的数据,我们可以把这些数据比作是被网粘住的小昆虫等。爬虫的作用就是去找到自己喜欢的口味,然后把它带回家,可以储存起来,也可以马上享受美味9 h; W3 p7 m+ ~/ M! |) M
所以说爬虫分为三部曲:& b1 L+ {9 ?2 ?& J- ^+ h
1、明确你自己喜欢什么口味(制定需求,明确你需要的数据类型)5 ?; a; n G' M) w/ P" x
2、去找到你喜欢的食物的位置(得到目标地址)
0 H/ c4 M1 o. P% |. s: i; b2 m3、把食物搬回家去(解析网址,获取数据,存储数据)
% L; m2 }) k) A) _它的整个流程就是:(简单的通过request请求获取数据并解析获取数据。以下都是固定化格式,可以照搬)
6 O$ C( V c3 r1 K; Ja、导入需要的库 requests3 u3 _7 l! q7 d& ^/ U$ a& @) a
& [' b$ p1 T9 ] B& Q4 f
import requests
& V) q" Q0 m- D& s8 c1
, a& v2 ?! c! | x8 z+ _. ^b、明确你要获取数据的网址(这里以百度网站为例)6 E: U: \9 X" d6 J
/ Y7 t( F# y1 j" \; _- h# b6 q8 R1 u
url = 'http://www.baidu.com'+ j2 z# `" V$ k; Y' M s _7 Q
10 F; u% ~: I# O, r" ~/ h
c、创建请求
- |8 V3 p1 E0 l2 [0 e2 g* i/ B) l- L" G8 Y* }
response = requests.get(url)4 K7 e. b0 k0 A: U3 F' B
1
+ n, }4 h6 k7 c+ h* y3 t6 R/ E. zd、测试请求是否成功(在实际应用中用的比较少,正常情况都是可以请求成功的,网站对于访问外部信息的爬虫是不会做出限制的)
7 d2 H9 D+ Y Z9 |# o% q( t0 u+ x" d
a8 M" D6 b( _- d7 ]/ r: uprint("状态码:",response.status_code)* v6 \- s" W$ y% S. E
1* ] j* b/ O" E5 Q1 z
当状态码为“200”时表示请求成功;如果不是“200”,很大可能就是你的目标url写错了,核对一下url
0 {7 s3 s9 H, x) Ie、得到网页源码& p& x* ?9 X7 o F% \# g
; o) T8 Q3 S8 Z2 u* j; m5 ]
print("内容:",response.text)
; f$ e: D/ w+ [& u& J1
3 y9 g2 a( H& Z$ x+ Jresponse.content是response.text的二进制形式# k( d; E6 K. z$ `5 N
' j) d& j+ n4 Q
至此,一个简单的爬虫请求就算是完成了。0 Y) b' e# w( f l
当我们请求目标url并获取到response后,就需要进行下一步:解析网址并获取数据
, ~0 W: X& S0 @$ |6 H* ^f、解析网址
( D9 N8 L* g5 G9 D: p& Z刚开始学习阶段,我们最常用的两种方法,一种是BeautifulSoup,一种是etree。其中BeautifulSoup是最常用的。以下将对两种方法分别进行介绍 (以下方法均为测试用例,实际当中应结合自己的实际情况选择应用)" A' v$ W& |9 M5 y
BeautifulSoup:" n8 p0 q' y j, T* E8 z
首先导入需要的库文件:
+ o" e3 r/ h% L; h) Q; i6 ]
0 e3 b5 C; M. P: V) c! ^from bs4 import BeautifulSoup
9 ` a5 F$ F7 ]) R' F/ f3 r11 Z2 `' h8 p- V. |4 R8 i8 `# p
然后对上面请求得到的response进行解析:/ N+ X! \7 D7 k
C ^! E! L, l; ohtml = respone.content.decode('utf-8')
0 U; |4 ^8 ?2 B0 dsoup = BeautifulSoup(html, 'lxml')
- J; ] h+ v- [: X( M; @1 [7 o& T p6 e6 f6 U
21 |4 a; H( q, x4 a P2 l) T
以下是BeautifulSoup中比较常见的方法,有兴趣的朋友可以去一一测试:
( P$ u, |: J& |% K$ v# 获取head标签
$ {/ D: t0 P% Y3 Kprint('head标签内容', soup.head)
: u8 L+ O! \# |1 z: m# 获取title标签1 S3 x, M0 i( Q/ ^7 l
print('head标签内容', soup.title)6 ~. B5 b4 }9 ]8 C
# 获取body里面的img内容
! N, f/ y/ R( k+ ` B; `# 通过点号的方式只能获取 下属第一个标签(即获取soup下面第一个body里的第一个a标签的第一个img标签)
' b; o) Q3 \% r+ r+ ~ z B% zprint(soup.body.a.img) 2 n( |6 B6 ?# H2 F" j
# 获取所有的img标签 使用find_all()搜索整个soup对象
2 w/ Z: h& x2 I5 hprint("获取所有的img标签", soup.find_all('img'))
" P5 S8 @- D# O& J1 Z% F# 获取标签中的属性src地址
* E8 |7 a! @" \print("获取标签中的属性src地址:", soup.img['src']) # 注意:英文点号都只能获取第一个值
5 \5 u. Y. U9 y; l
; B& |5 F4 `2 j; [6 G' G' {
4 G- L5 F6 \) b K, ]% l* f/ |# |# 获取soup的name
( p" v! m( H# H% f5 U0 a. i# k @print("获取soup的name:",soup.name)
# Z7 B( m" U) }5 f" d- }- ]# 获取a标签名
+ m4 [& X$ C% m, r/ ]print("a标签名字:",soup.a.name)/ ?! C: L0 D2 F: ?" t% _* d
tag = soup.a
) [* `. S9 M6 S, z4 kprint(tag)
; d$ n8 o# y9 V# 修改操作 a标签改为b标签% R$ s6 h9 n4 d6 Z$ Q+ {
tag.name = 'b' # 赋值后<a> </a>变为<b> </b>
) D) N- f/ t& R( h# 输出修改后的内容3 {) e/ P$ g2 {) F
print("输出修改后的内容:",tag)
6 P5 J/ M) I0 B# 获取全部的属性 attrs
* X8 Q4 l Q7 C4 eprint("tag对象的全部属性:",tag.attrs) # 只能得到当前标签的属性(不包含下属标签)
8 F( e0 n8 K+ t' K4 U: t, m% q& d: Q% z# j8 U2 X
# 获取属性的class的值 根据键取值
- \6 g; n% U) D3 P# Z7 t5 L' dprint("获取属性的class的值:",tag["class"])/ K5 e) F) @& Z$ `" B' i$ m$ ~
. y9 k4 Y5 Y/ r. L- ^
# I& m8 d9 ^9 O0 ?) E7 o. `' o3 G1 y' {: V4 I
" L6 i! q' F& w- k4 v
"""针对获取的标签属性可以进行增删改查"""
/ D- z6 X- X* v/ B( u# 修改. J9 k0 T3 q9 c& p1 g0 b8 P E- I
tag["class"] = "Logo"
9 x7 f6 e4 y; A" iprint("tag对象的全部属性:",tag.attrs)
, Y/ P1 ~3 a% n. a# 输出属性" u2 _1 C; \, `# k% s& ^4 `
print("获取属性的class的值:",tag["class"])4 q% h2 D9 Z: z9 o
# 新增 属性id 赋值logo
+ x7 c* |- a8 ~tag['id'] = 'logo'
/ S2 V5 G5 M D, z' X0 I7 J* Uprint("tag对象的全部属性:",tag.attrs)
# I8 Q4 X0 [7 x, v. t5 Q$ G# 删除属性# S3 z! K# [2 ?( F) M
del tag['class']
9 ~# I/ p5 x5 ^. e( Yprint("tag对象的全部属性:",tag.attrs)# z+ ]) ^" g3 G1 e# ^
$ i' V T' E* m+ A7 @7 ~- u
$ |: Z" x- K' M2 D7 b; [5 N
) N; Q: ?! G! K( ]7 J, @
"""针对内容操作 (只针对标签,对属性无效)"""
: ^( ? O/ a4 G1 N+ Q# 获取title标签内容7 a# d' m% _0 ?, Q
tag = soup.title* K* Y" U3 }0 @1 P5 ^: C* w
# 获取title字符串
9 k& N/ z. X6 z) f0 kprint("tag对象所包含的字符串:", tag.string)& H! R# G2 Q5 v7 ]2 ?
print("类型:", type(tag.string))
5 n1 M9 x3 j- @9 C) g% e" V# 替换内容
6 m, h' Z3 O5 Z2 U5 Ztag.string.replace_with("你好"). `: {& V, [% @ i+ G4 g7 k
print(tag.string)
5 H0 z3 L; a5 i9 v- t# <!-- 学科建设 -->& V3 J8 g* X( g
# 获取注释文本内容 ~& m, a9 W% q# l y# Q
markup = '<b><!-- 学科建设 --></c>'
8 E5 a* Q, E$ Vsoup_comment = BeautifulSoup(markup, 'lxml')
3 `0 C) h( c; p* J7 k Icomment = soup_comment.b.string # 以markup第一个标签作为关键进行搜索
2 h+ Z; `; \; Q) ~3 Cprint("获取注释文本内容:", comment)3 Y9 S# M7 i D; y, u1 o
# get_text()- y& @; e5 F' ~0 F& p% f
print("title的全部节点:",soup.find_all("title"))
5 M. l. x+ x7 Y& O7 N9 t1 m3 vprint("title的内容:",soup.title.get_text())8 }8 g$ g/ K0 n4 _3 `, f
"""查找ul元素标签""", `) ], ]; k* X" b: y4 { a
# class是关键名,匹配时后面必须加下划线_- ?" ~4 P9 q* y$ ^( ^
# tag = soup.find_all("ul", class_='menu') # 按照css类名完全匹配4 O; M+ O- G( Q+ Q
# print(tag)3 C- F$ e/ {5 z2 Q( a9 B
tag = soup.find_all("ul", id='menu') # 按照css类名完全匹配
3 m4 w! Y/ U4 _9 r% @) oprint(tag). _* W! o0 ^# E4 o1 V. Z% e. E
# 查找名称为a元素的标签内容7 |# r3 z" e$ o) j8 Z. V
taga = soup.find_all('a')6 }0 v( n9 E, ?- X1 E* J; |" T
for tag in taga:: x+ u; w' S5 h. {- u
print("查找名称为a元素的标签内容:", tag.string); P+ ~- \3 A( ~3 c9 g% @# W
# get 获取属性信息 获取整个页面的img标签图片和src属性值8 W. e1 Z0 }* t1 G3 K; m. r V
tagings = soup.find_all('img')
* N9 H+ z- G$ W8 sprint(tagings)8 _, }. S9 r) q+ P7 r! s0 u
# 循环输出图片地址
3 q2 i' s8 n) e/ u. afor imgsrc in tagings: _) c( ]8 l9 d$ c$ N
print(url+imgsrc.get('src'))
6 F: A4 L* c1 F; M9 f6 X- V- w3 @: P4 X6 B" E4 c
""""属性只能做为参数,所有的操作只能针对标签"""0 w, |( A4 F' T q: o
! K/ s% [9 K3 q$ R( {etree方法:9 d5 S) a! U2 O% w8 T
导入库文件:3 J0 i- |6 Q' Q, c" g
/ o5 `# J8 n9 T: f; t) w
from lxml import etree. Q+ W& T: K6 L: a
1
$ w+ F9 c: C; V4 ]7 G. Z$ o解析得到的response对象;
4 k/ {; F% M* J" G# C( X
0 e K" U: x: x4 _4 k& f, S# 设置response的字符集
, w0 l" k; W! p& z( N4 whtml = req.content.decode('utf-8')7 X! ] l3 h9 B; r8 x+ `6 Z
# 解析对象' W8 b9 J( L. M
html = etree.HTML(html,parser=etree.HTMLParser(encoding='utf-8'))/ M5 i, L$ ^" v# h8 a; v! [2 e
, M2 q" [0 V) z9 w$ z
常用的方法:
; N. V( Q& y! p' b9 |) w+ j; |8 M- \% U! O% z% y/ Q
( d, W* F- t2 n
# 定位head节点(元素)# x' V6 l; [+ o6 n8 x1 P
result1 = html.xpath('head')
# n$ e" X+ U9 b6 d6 Oprint(result1)
* @- K, ^) f# b. m4 }8 {# 定位title节点" @; N( J% H, B B
result2 = html.xpath('/html/head/title')+ Z- [( r2 O2 i
print(result2), ^, R9 ^) n A! d
# 搜索节点 title节点
6 H' R" L l' F8 W6 V0 W1 c7 k7 fresult3 = html.xpath('//title')
/ V$ K2 R' P" x4 O8 D, M$ Sprint(result3)
+ @/ C% S0 _9 V# 搜索title内容 text()得到文本信息; p0 m$ S/ n2 q# w9 s: p1 a
result4 = html.xpath("//title/text()")
4 {2 m1 g" w2 i. i. oprint(result4)+ C4 S# K! O% r* [7 @# \
# 搜索div节点
6 M5 V# |! w' v$ h0 |result5 = html.xpath('//div')
! Z8 z1 L! y8 n- b$ Dprint(result5)9 K6 K9 Q: R" \8 G' F5 ?* A
# 搜索div节点 并用class属性定位
8 l7 d* g, H0 M& S7 Z& mresult6 = html.xpath('//div[@class="news"]')5 \7 |5 H* _( t. ^1 [: J, z
print(result6)
" N# \7 H+ z& I* B K# 搜索div节点 id属性定位: i- q) [; p- j
result7 = html.xpath('//div[@id="news"]')' Z3 ]0 l: G( n4 {! k) g- k
print(result7)
; S& e7 J/ z* F4 o& U# G$ u# 获取列表span信息/ D4 L6 r. Q( `0 r4 C2 Y
text = html.xpath('//div[@class="news"]/a/span/text()')
: d# |3 W' T. |) a# s9 Y b# H) Iprint(text), m% t$ u6 r @ \8 g% m
& E8 k N7 g8 h- }! @* R
g、通过上一步我们得到自己需要的数据后,下一步就是将我们得到的数据进行保存' w- r% {8 p7 k: D# W1 B
保存的方式有很多种:
C+ B6 s! ~" r; L- r; s1、保存至文件
8 I- D0 ^5 E6 X4 b* |csv、json、text
8 ~- q; s1 T4 X& j' {; A2、保存至数据库 r' k; q$ w5 H; [ d% l
MySql、MongoDB、Redis 等 (目前主流的为以上列举的三种数据库)
关于数据存储后面再做详细介绍
4 l0 d3 Q: N1 V7 b; J0 n- H% W: }1 |& G
. ?* L2 T" q1 T
————————————————
! e- m' i% G, d% K$ `; R版权声明:本文为CSDN博主「royallucky」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
/ e0 S3 o! m" @1 J原文链接:https://blog.csdn.net/royallucky/article/details/1059304739 `( j/ m. W* \9 [: s8 y
6 m# D& w/ P# |0 \5 c- a9 I
1 y( c$ P' J# d$ f4 M4 Y0 Y
作者: 建模小白12138 时间: 2020-5-5 20:43
感谢楼主,,,,,,,,,,,,,,。. _$ D9 J d' v }' _( w
| 欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) |
Powered by Discuz! X2.5 |