在线时间 1630 小时 最后登录 2024-1-29 注册时间 2017-5-16 听众数 82 收听数 1 能力 120 分 体力 563329 点 威望 12 点 阅读权限 255 积分 174222 相册 1 日志 0 记录 0 帖子 5313 主题 5273 精华 3 分享 0 好友 163
TA的每日心情 开心 2021-8-11 17:59
签到天数: 17 天
[LV.4]偶尔看看III
网络挑战赛参赛者
网络挑战赛参赛者
自我介绍 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
群组 : 2018美赛大象算法课程
群组 : 2018美赛护航培训课程
群组 : 2019年 数学中国站长建
群组 : 2019年数据分析师课程
群组 : 2018年大象老师国赛优
% ?/ g7 O1 e+ u. T' w9 p
+ j- t$ p4 u5 O
% a- E, ]& o( N8 g) t9 O: {; [
手把手带你5分钟搞定爬虫(聚焦爬虫)
# V9 ]6 S4 C) V( ^3 v( f
5 t; a& {' v4 h9 E+ I
爬虫的原理
2 g! Q4 W/ C4 j % ~* }2 U( e! M- z9 O$ Z
对于很多刚入门的小伙伴来说,了解爬虫的工作原理是非常重要的。只有当你了解了它的原理,你才能结合实际情况写出对应的爬虫。下面我将以通俗的语言方式来介绍爬虫( a S7 ]) i! c O8 N! d0 _7 ]# t
把互联网比作一张巨大的网,那爬虫就是这张网上面的一只小蜘蛛,在互联网上面有很多的数据,各种各样的数据,我们可以把这些数据比作是被网粘住的小昆虫等。爬虫的作用就是去找到自己喜欢的口味,然后把它带回家,可以储存起来,也可以马上享受美味
! W* i1 n' Z8 h3 r) F7 L 所以说爬虫分为三部曲:
4 E, x+ E: u S+ p3 f* ^ 1、明确你自己喜欢什么口味(制定需求,明确你需要的数据类型)5 u# ?# f: M/ K4 V2 v4 _
2、去找到你喜欢的食物的位置(得到目标地址)
$ k& m- j: I2 N0 G 3、把食物搬回家去(解析网址,获取数据,存储数据)
4 P! r' v- a+ e# l7 X# t 它的整个流程就是:(简单的通过request请求获取数据并解析获取数据。以下都是固定化格式,可以照搬)/ n. H) [) n/ N3 p; A
a、导入需要的库 requests
3 R- h1 W' |' z8 R' I) @1 |# N) v # _* m) L/ k+ m# N
import requests
- `. A. K) [1 p 13 p( D+ V$ e% E ^, E4 J
b、明确你要获取数据的网址(这里以百度网站为例)# U1 N V6 Y% F8 J0 u2 E! R2 T
/ Y0 r( d% p' ?- _5 A2 V url = 'http://www.baidu.com'
) u9 x" `2 C1 B+ _2 h1 g0 ` 1+ F3 `& _+ G5 X' N
c、创建请求8 B5 S3 F2 I8 {& Z
; B$ F( K% \' C response = requests.get(url)8 l6 Q2 [( {5 d' H- K3 m0 |
1 S- |! |" Q# R* U2 K5 f2 W
d、测试请求是否成功(在实际应用中用的比较少,正常情况都是可以请求成功的,网站对于访问外部信息的爬虫是不会做出限制的)
7 [' d, M5 I( t* n! D) C # s' ]" b6 j" [! ?+ x Z+ \
print("状态码:",response.status_code)6 c0 C2 D5 z N- O A6 {6 g
1! E1 t! L" u+ m, F2 K! z
当状态码为“200”时表示请求成功;如果不是“200”,很大可能就是你的目标url写错了,核对一下url
p( w" r" K7 Q e、得到网页源码4 b6 A; B# i6 r
# L2 _# K; ?. x4 x$ X- q! _5 V
print("内容:",response.text)
: H8 S0 \; R8 G$ ] 1
* o4 g/ u1 m o1 e. I/ g$ |7 D& ^ response.content是response.text的二进制形式
6 {& f. m x, {# U5 P 4 G/ f) n) [' p/ j* e. K7 t$ J
至此,一个简单的爬虫请求就算是完成了。' I3 H8 ?! V3 z: `+ q! I" z* H
当我们请求目标url并获取到response后,就需要进行下一步:解析网址并获取数据6 x' X$ F/ \+ g0 v" `% h
f、解析网址
/ Y% v6 s$ C4 r/ B j( O% u 刚开始学习阶段,我们最常用的两种方法,一种是BeautifulSoup,一种是etree。其中BeautifulSoup是最常用的。以下将对两种方法分别进行介绍 (以下方法均为测试用例,实际当中应结合自己的实际情况选择应用)
) p/ E6 N" s) b5 a% W2 }; U3 z BeautifulSoup:7 z/ m6 r0 \& ]3 Q8 n% w/ @, N
首先导入需要的库文件:
" F0 I" k; e1 U, B, q $ }4 C+ k1 l) [+ [4 F+ _; J
from bs4 import BeautifulSoup
! M6 S- B9 U3 n 1
2 T+ K1 a$ n( x, w" Q$ M9 w 然后对上面请求得到的response进行解析:/ }4 c% _4 l& W; v) g& V
" G' k- q& O$ M html = respone.content.decode('utf-8')
% [5 i& b! X7 `4 f soup = BeautifulSoup(html, 'lxml')
+ P, N' a( x& W1 ? 1* ^) Y( \0 ?9 A# }: Z8 A0 T8 y& c- a
2
/ ?9 n! c1 J) B- @9 p9 }3 j; e 以下是BeautifulSoup中比较常见的方法,有兴趣的朋友可以去一一测试:
& T5 w0 w- S+ m& g9 l5 S # 获取head标签
U+ I5 r& P7 h7 b: G3 N print('head标签内容', soup.head)3 h$ i4 s4 z% c% S; |& H7 a* X
# 获取title标签$ A: V% x' [- z4 w3 J/ @9 A" C- M: j' f
print('head标签内容', soup.title). r; M* ]1 `- i! f Q
# 获取body里面的img内容
( `. G' v0 u8 k" N8 H # 通过点号的方式只能获取 下属第一个标签(即获取soup下面第一个body里的第一个a标签的第一个img标签). X- O3 o- k) F) m
print(soup.body.a.img)
) P9 V0 x" O! ? n4 u # 获取所有的img标签 使用find_all()搜索整个soup对象6 z; P* p. O8 J. ^" D D
print("获取所有的img标签", soup.find_all('img'))
' n; ` g) l% k2 D' q8 c: P # 获取标签中的属性src地址0 G5 j9 m. ^# x5 M) P; j3 S
print("获取标签中的属性src地址:", soup.img['src']) # 注意:英文点号都只能获取第一个值
h2 }% H, C, V/ Y w" X 6 n% |5 |* M/ Q* g* M( X
; N3 t2 F& J& @
# 获取soup的name! N# z/ l0 l) F' t- l' G& Q6 |
print("获取soup的name:",soup.name)* W. d! t3 T9 ~6 v
# 获取a标签名
m* X: X& ]: ^5 K% _5 Y print("a标签名字:",soup.a.name) W) W4 Y1 P# i# g/ j
tag = soup.a0 p# K9 z4 t' P6 O* S
print(tag)) v1 L3 {8 S) Q
# 修改操作 a标签改为b标签8 e; t1 S# `; X3 Q. l
tag.name = 'b' # 赋值后<a> </a>变为<b> </b>
$ e8 v9 t* G: d$ x # 输出修改后的内容
4 w; `9 |$ Y4 t, f! N. W% W print("输出修改后的内容:",tag)
( O2 o. g+ J2 d# \( ^/ r) W( ?* i! s # 获取全部的属性 attrs, j' g" r6 l& f. t
print("tag对象的全部属性:",tag.attrs) # 只能得到当前标签的属性(不包含下属标签)
0 ^6 Y: a% J2 z : \2 O- q7 e+ C2 k" l
# 获取属性的class的值 根据键取值
+ Y0 v+ f' g1 J4 l print("获取属性的class的值:",tag["class"])- u Z) Y5 w) l" e3 b
" X2 z7 j" O" H6 p( l M/ Y" J b# }# c8 {. }2 m# }/ \
6 N6 o& w1 J: k: Z% v; q # d& K1 N" R3 I* u0 |" K' y4 f
"""针对获取的标签属性可以进行增删改查"""( G! _7 d L2 y/ _) P3 w+ E
# 修改
0 Y% \3 A2 T- _* C2 B tag["class"] = "Logo"
8 t+ Y. r9 o4 \+ R- y1 J print("tag对象的全部属性:",tag.attrs)" U1 u; i8 _7 Y+ t
# 输出属性
. V- A4 Z) V7 d$ `( j print("获取属性的class的值:",tag["class"])1 y$ L. V+ t" w1 \3 R, L
# 新增 属性id 赋值logo
. C9 g. s! H: }4 ` tag['id'] = 'logo'
- E7 M+ B6 ]# {4 p* A; z print("tag对象的全部属性:",tag.attrs)
* Q) \! |9 I1 h; T0 `" f: k # 删除属性
3 F& L, |' H) _4 p del tag['class']
( Y A# ^1 p2 e3 H8 h& h8 O print("tag对象的全部属性:",tag.attrs)
8 `' g% [9 W2 q$ n1 T! R, w
, O5 ~. {3 G' _# p! R2 u 7 E& q6 W/ _3 Z1 H4 ^7 M) P
2 J) Y1 l) ~6 a( A7 s. _$ X- A, k
"""针对内容操作 (只针对标签,对属性无效)"""
4 C c* x& v. N5 q # 获取title标签内容& a, |. ]2 ^% L7 i' N
tag = soup.title
) Y0 G5 q N% p/ V6 S* S # 获取title字符串
! h q/ O* e: `3 y+ k$ x# \ print("tag对象所包含的字符串:", tag.string)
- g7 E; j6 S: q) O* n& y) p print("类型:", type(tag.string))
4 e7 H w3 N2 ] # 替换内容6 y' ~) @0 F1 e
tag.string.replace_with("你好")
9 h( |8 a6 ~) I- b2 q F! Z print(tag.string)
2 E( l" p- v7 c # <!-- 学科建设 -->- G8 u9 l" c8 b7 U
# 获取注释文本内容
: q: q3 P. f6 q' @) x markup = '<b><!-- 学科建设 --></c>'2 A, n1 X0 l0 W1 F$ ^
soup_comment = BeautifulSoup(markup, 'lxml')
1 D; v6 u8 G: \3 J- A6 V1 C comment = soup_comment.b.string # 以markup第一个标签作为关键进行搜索% {8 Z+ S7 l9 h! g+ W
print("获取注释文本内容:", comment)* m) Z+ ~5 l. X
# get_text()
. r& w, ~( [5 N2 Z X6 o: p print("title的全部节点:",soup.find_all("title"))
& s1 r* Q3 z' ~/ L0 `$ E print("title的内容:",soup.title.get_text())
) h/ R. u# I4 H3 ^ """查找ul元素标签""" M( L' U+ A# k" F) q1 b
# class是关键名,匹配时后面必须加下划线_9 C. N6 u: s% R2 ]+ a/ P, E" D
# tag = soup.find_all("ul", class_='menu') # 按照css类名完全匹配
7 E2 y$ g3 G$ A, b3 K5 B; I8 Z # print(tag)
4 t* [4 x: \3 e& ] tag = soup.find_all("ul", id='menu') # 按照css类名完全匹配
# w* h5 V6 }& ?8 O/ W7 U print(tag)' a4 `3 R4 z4 Q( s; v
# 查找名称为a元素的标签内容
! ~: y5 m& J- a8 H& E i taga = soup.find_all('a')
( y4 C& ~; w& G1 Z for tag in taga:
. h" K4 X8 M7 N5 B1 N# M# c2 | print("查找名称为a元素的标签内容:", tag.string)
5 _* S. C& O$ H5 a3 o* b$ v* p # get 获取属性信息 获取整个页面的img标签图片和src属性值& O1 ^( B9 F! ?
tagings = soup.find_all('img')
1 s% {% C9 v, w C5 x6 o print(tagings)- R* A k# @" w4 ]
# 循环输出图片地址
% c+ z4 o5 L% m `3 k! y for imgsrc in tagings:
0 ^) K0 J6 \* z3 T! V8 e) n print(url+imgsrc.get('src'))
3 ]2 q4 Y: j4 Z. N: b$ d6 `$ N# N ' R% h% f* g, X7 i, }7 b; ^
""""属性只能做为参数,所有的操作只能针对标签"""6 E6 J0 A0 ]8 G% H' f/ X( V
5 z7 b1 Y4 @( [( t etree方法:' m; g& E. p) c- @0 ~( {- i: L
导入库文件:9 Y5 o# k' t$ Q! K% t0 L
6 v e' O$ D6 m0 r$ x; j from lxml import etree# x# d; C9 r/ o
1
0 F6 |7 I: J: N3 G) b 解析得到的response对象;
: l7 X4 ]: J& ?3 @- }
! r, H6 `! H8 C # 设置response的字符集
B) t/ A& \% u7 ` html = req.content.decode('utf-8')
p2 L! C8 p& y& S: o4 f3 o # 解析对象
" Y/ ~/ q) e A0 K6 e1 d; R) F html = etree.HTML(html,parser=etree.HTMLParser(encoding='utf-8')): r, ~# ~6 t9 l( @0 z2 W
% W* g* j" `1 r6 V6 c% ^ 常用的方法:
5 i1 b) L3 ~! z+ C
+ b) o/ Z* c" K' @. w- `8 {
/ C6 m# b' V6 r+ Y4 W/ r # 定位head节点(元素)
2 T2 R) {8 Y8 ^ result1 = html.xpath('head')! @# v1 ] ~6 E7 Y, i7 @
print(result1)$ T6 _" X. @, {; c/ g
# 定位title节点
; j* e; W1 i: v' U; ?+ B, | result2 = html.xpath('/html/head/title')
9 I J* r( y" K print(result2)1 H2 g" |' h6 z7 @' n: A! `
# 搜索节点 title节点& u: D9 m' D9 T; u
result3 = html.xpath('//title') O `6 I7 a; f- A E
print(result3)1 q( u( x# C. z& r' X! n- V/ x
# 搜索title内容 text()得到文本信息
; c$ E. t# T4 G! U result4 = html.xpath("//title/text()")
" K8 | x/ o# E3 \8 r print(result4)
8 J r, w' M% ]5 B; n # 搜索div节点/ c1 B* o1 \$ A0 g" d
result5 = html.xpath('//div')
2 N2 X }) z4 I print(result5)
) M' q% J2 F/ F" Q# E5 t # 搜索div节点 并用class属性定位
& V- M) B( a& m) [3 Q result6 = html.xpath('//div[@class="news"]')
! m: E1 Q4 D, V5 A6 [8 Q print(result6)
( C! g! |+ L! ? # 搜索div节点 id属性定位
* Z. U" H/ e! G result7 = html.xpath('//div[@id="news"]')
( O, {4 _1 C2 X1 Z print(result7)
- G# L0 t# G' b5 x$ R( D # 获取列表span信息
7 q* k/ P) v9 _# b- I4 i# ` text = html.xpath('//div[@class="news"]/a/span/text()')
6 z' ]3 y: [ J* y/ ] print(text)
" |- c; b( [9 y' ] 8 C' t. a9 J+ ~3 c' o- t: T
g、通过上一步我们得到自己需要的数据后,下一步就是将我们得到的数据进行保存8 e0 ~- N/ o9 f
保存的方式有很多种:( E+ q0 ~: ^% i! L
1、保存至文件
7 q, J; D6 Y9 Y: ] csv、json、text& I9 v$ a) \0 n2 ?2 x5 [! \7 k
2、保存至数据库
! O5 @5 z: C/ \0 N6 D0 G# }+ I MySql、MongoDB、Redis 等 (目前主流的为以上列举的三种数据库)
关于数据存储后面再做详细介绍
" X1 h& \" C! [0 }; z, \
f+ I, J2 i7 K5 F7 J! e9 T3 G9 \- r
/ C o' n. w$ Y6 a0 ], z ————————————————
$ `3 B- C' }. X h' ^2 n. h 版权声明:本文为CSDN博主「royallucky」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
; V. { c5 K: O, X6 P1 s 原文链接:https://blog.csdn.net/royallucky/article/details/105930473
" J0 j. H) q' [" r K! \ 2 ^- k5 ~/ r! z/ g! \, O
# ?) X. c* K G0 v, T& i# Y
zan