数学建模社区-数学中国

标题: 手把手带你5分钟搞定爬虫(聚焦爬虫) [打印本页]

作者: 杨利霞    时间: 2020-5-5 14:21
标题: 手把手带你5分钟搞定爬虫(聚焦爬虫)
8 A) O. _4 B5 @# s. H- ^7 K
2 R2 F4 i, F9 S" ?! E) f/ ?& ^
% |9 C* d8 S0 a: }) n, E
手把手带你5分钟搞定爬虫(聚焦爬虫)
4 }9 X9 j( j" k' w# q* S, I
  _! R+ F. r* q6 |6 |$ o3 _
爬虫的原理
4 U: _  Y' H4 }4 P3 t# d6 t8 Y) y8 g2 \
对于很多刚入门的小伙伴来说,了解爬虫的工作原理是非常重要的。只有当你了解了它的原理,你才能结合实际情况写出对应的爬虫。下面我将以通俗的语言方式来介绍爬虫1 W0 t1 T2 z. y8 ^+ e; X/ ]
把互联网比作一张巨大的网,那爬虫就是这张网上面的一只小蜘蛛,在互联网上面有很多的数据,各种各样的数据,我们可以把这些数据比作是被网粘住的小昆虫等。爬虫的作用就是去找到自己喜欢的口味,然后把它带回家,可以储存起来,也可以马上享受美味# V7 ?7 o" v- {4 C6 T/ e# s- ~
所以说爬虫分为三部曲:$ _- |; F6 G, y0 R4 x
1、明确你自己喜欢什么口味(制定需求,明确你需要的数据类型)& G/ [2 p; e/ G# Q5 s
2、去找到你喜欢的食物的位置(得到目标地址)
! S( J. [+ r+ I# ~/ a# M3、把食物搬回家去(解析网址,获取数据,存储数据). y: }0 v! D* ]8 M& S. p: S
它的整个流程就是:(简单的通过request请求获取数据并解析获取数据。以下都是固定化格式,可以照搬)7 Y+ N' }- E5 F4 }, [+ m
a、导入需要的库 requests
6 W( c2 i3 ]$ `) P3 L; A! v7 ~5 g9 b% Y7 ^
import requests
3 D# S: g3 Z' x; T: Y15 N8 L& C% V  D0 J. \. m
b、明确你要获取数据的网址(这里以百度网站为例)
9 e1 y. u* [1 k+ m* r1 r) T* t; O/ @0 E6 d
url = 'http://www.baidu.com'
; D5 w% I1 n" {4 x1
% V; Y/ r" P' Y' n# a  ^0 w% wc、创建请求
, H  d4 m) N) L4 R6 [, v1 q9 b4 t8 D5 r; ?2 a
response =  requests.get(url)
! r" N4 {% f- ~- r12 o  O7 C8 a9 b2 p
d、测试请求是否成功(在实际应用中用的比较少,正常情况都是可以请求成功的,网站对于访问外部信息的爬虫是不会做出限制的). p& `* Y- a8 C5 {
  ]3 K# z3 R% h& j) E! D, E
print("状态码:",response.status_code)6 q7 u. s# s( B/ l/ j
11 f$ A' r, T& J/ ?4 c% x  n
当状态码为“200”时表示请求成功;如果不是“200”,很大可能就是你的目标url写错了,核对一下url9 }& |' c$ N% y- Y9 v1 A8 X
e、得到网页源码+ V6 N2 Z$ t, ~

7 F/ ^0 t6 Q7 _* L: a* [9 mprint("内容:",response.text)
8 k0 p3 F9 g! {/ V3 a2 c1" Q$ J6 i7 g) E3 B6 _, B
response.content是response.text的二进制形式$ k! ^7 D* c8 @

( ?8 D4 Y0 |: `: j3 [( _- O至此,一个简单的爬虫请求就算是完成了。+ @6 X* Z. R" X- |4 q# A
当我们请求目标url并获取到response后,就需要进行下一步:解析网址并获取数据
' {3 N, G% T5 x6 lf、解析网址
/ V$ d0 s) o- }' M  c刚开始学习阶段,我们最常用的两种方法,一种是BeautifulSoup,一种是etree。其中BeautifulSoup是最常用的。以下将对两种方法分别进行介绍 (以下方法均为测试用例,实际当中应结合自己的实际情况选择应用)0 s$ {, C: @* h* ]2 _, g
BeautifulSoup:
, y* @- d9 t3 G: O首先导入需要的库文件:
+ T5 `" H3 ]5 G) h# ?$ i5 w
3 l# x7 Q1 M+ B% T& afrom bs4 import BeautifulSoup
1 ?  {4 D  m) z6 ]4 H* D' w2 v1* f4 I! c9 |! x/ m
然后对上面请求得到的response进行解析:
0 `; v/ m  m! U8 s1 u5 g
: A- N' A0 m1 h  C; |html = respone.content.decode('utf-8')  a, Q7 M0 E1 c8 |
soup = BeautifulSoup(html, 'lxml')
/ M, Z& K! B  B$ }( V( V1 o9 Q1
4 S7 g5 l9 J0 q9 _1 R+ w, I( i2
/ \; e: h8 S. B* v, G以下是BeautifulSoup中比较常见的方法,有兴趣的朋友可以去一一测试:
3 b5 t- ^6 A6 j. x% W# 获取head标签. S9 @- M6 @/ u& G4 _; x9 R
print('head标签内容', soup.head)
" H: t  s/ U2 `( _# c2 y" t9 A3 ]# 获取title标签: @8 W* y8 Y, A# B  }  e
print('head标签内容', soup.title)
" ]4 `. p6 e. D6 [: Q# 获取body里面的img内容
& {, ?* X7 _! N4 `2 e0 |# 通过点号的方式只能获取 下属第一个标签(即获取soup下面第一个body里的第一个a标签的第一个img标签)& h7 p4 y* y& Y, }. O* c
print(soup.body.a.img)   $ R8 N' q7 ^1 Q6 F$ d5 g0 [0 {
# 获取所有的img标签  使用find_all()搜索整个soup对象
# `( k& c7 w0 ^% x( mprint("获取所有的img标签", soup.find_all('img'))
7 p8 D' G0 I6 i- c# 获取标签中的属性src地址
6 k# _3 @# F" u; o1 ^print("获取标签中的属性src地址:", soup.img['src'])      # 注意:英文点号都只能获取第一个值
( W9 V$ w: t9 E9 |8 _0 \' V% |$ c$ T* q2 H

. X1 {; Y/ |- U1 I# 获取soup的name
' _0 R  l# A# k; u' rprint("获取soup的name:",soup.name)7 E" H: l; h  K" L3 z! z
# 获取a标签名
% }. M. z( m* v1 _% xprint("a标签名字:",soup.a.name)
3 L8 Q. ~! \9 Utag = soup.a3 \0 I7 N" t: \5 ~9 \
print(tag)$ S0 a1 U$ C0 a- J7 [; |7 T' N
# 修改操作  a标签改为b标签9 B3 }' D2 @3 [/ l0 r
tag.name = 'b'   # 赋值后<a> </a>变为<b> </b>
* N1 e9 h( R; }! o* W4 T# 输出修改后的内容
; {3 O+ B& l& ^# Y8 N- v- h$ a9 Oprint("输出修改后的内容:",tag)2 J) X% a* b* J
# 获取全部的属性 attrs. |& ]% ?% u# O0 m) O
print("tag对象的全部属性:",tag.attrs)   # 只能得到当前标签的属性(不包含下属标签)
0 @3 X  T: y* W+ \: o4 k/ o, h2 G1 V$ D5 [; w3 ]
# 获取属性的class的值   根据键取值6 C) w/ B1 o- k
print("获取属性的class的值:",tag["class"])
  g2 E7 t1 @- U$ A, |  X2 ?/ j2 M
/ [8 }( _- v( a; U( D1 _1 d

" d  D' u/ _; k6 v+ q* K3 f7 Y0 Z+ O; r' E+ ^! T
"""针对获取的标签属性可以进行增删改查"""
$ O3 b/ U  o3 X8 m) g* W# 修改
' J2 Z# P+ X9 a) _7 W& D, ?2 ktag["class"] = "Logo"
4 ?9 `# I& b1 q  ]4 Wprint("tag对象的全部属性:",tag.attrs)% t3 ~: c3 h" G6 @  v
# 输出属性# P" y, ?! U1 X, {
print("获取属性的class的值:",tag["class"])
+ b7 |+ @9 j4 a* e5 P* \" N3 I. k# 新增  属性id  赋值logo0 Z! [* W- v" @. y, [
tag['id'] = 'logo'
, N) c7 M! r0 Y5 ]1 }print("tag对象的全部属性:",tag.attrs)$ W1 P( P& ]# d3 ?
# 删除属性5 Q% Z3 j2 ], j  Y. j; N
del tag['class']
( g' O0 }, X1 x3 d- ]3 ^print("tag对象的全部属性:",tag.attrs)
' y% R4 ?& t" l: |/ U% B
5 Z: m2 K/ s3 ~' }9 A' u1 _" f3 {3 Q6 V0 q3 q) K* b% Y

5 M2 X% m& T8 W- S% N! T9 |"""针对内容操作  (只针对标签,对属性无效)"""
# e/ J8 J* U( R% V3 l/ e2 e: a# 获取title标签内容1 r. W$ ^( {6 W- l) X
tag = soup.title2 q, Y* ]. y1 _0 u5 }6 N: s
# 获取title字符串
* }8 O& C4 b! l" G: Qprint("tag对象所包含的字符串:", tag.string)8 v4 q9 ?* b* v; J. O7 v) h& j9 p
print("类型:", type(tag.string)); x/ A; F/ [& k) J% a3 M: `7 y
# 替换内容! {' E. M+ i. n6 ]
tag.string.replace_with("你好")
8 y: U; j- |- P0 d& O0 j, t& W* `  ^. Zprint(tag.string)
% c3 S4 t+ g! h- Z' \; c# <!-- 学科建设 -->
# f0 B3 e0 s& t: E# 获取注释文本内容; U% S% W' J  w1 b* ?
markup = '<b><!-- 学科建设 --></c>'- _3 l: a" ?; h: h
soup_comment = BeautifulSoup(markup, 'lxml')9 v- ]0 `2 F$ P" A
comment = soup_comment.b.string                    # 以markup第一个标签作为关键进行搜索
, R( e& R* b/ C. Z- {print("获取注释文本内容:", comment)
& ~# Q' h- S+ e9 b6 L, f) {0 u# get_text(); w* c0 w% X6 u( T: W  a
print("title的全部节点:",soup.find_all("title")), v# F  Y3 Y( y2 o
print("title的内容:",soup.title.get_text())
! `8 {* a% m  ]6 S! I"""查找ul元素标签"""
/ c! h/ _/ T* \  l2 @# class是关键名,匹配时后面必须加下划线_' i4 G) g& _  b* v
# tag = soup.find_all("ul", class_='menu')  # 按照css类名完全匹配
) o; ^- Y% Y% ~5 e# print(tag); l6 k2 H- }: X% j
tag = soup.find_all("ul", id='menu')  # 按照css类名完全匹配
5 N, q1 K+ R: }6 Uprint(tag)& X& N& g2 G( @4 I8 i
# 查找名称为a元素的标签内容. j! X0 P8 d& U6 o8 a# b
taga = soup.find_all('a')& T9 l$ W: N; v4 e/ i' Y
for tag in taga:9 Y& ?: W/ b( x
    print("查找名称为a元素的标签内容:", tag.string)
- c6 a: `9 N- }' R- f# get 获取属性信息  获取整个页面的img标签图片和src属性值
9 e, k  S: I! `1 y9 L& |3 l) k* Ztagings = soup.find_all('img')( Y( h; i  {7 C0 j! h: W3 R
print(tagings)  q! m9 U. x& u5 S! `5 v: D
# 循环输出图片地址
$ Q/ Y! Q; Q0 I" O) mfor imgsrc in tagings:2 ]' z, V0 o  m5 v* }" u
    print(url+imgsrc.get('src'))
5 q  e: G& g. J: A$ u. p' b5 A, g% h3 c2 G4 y% [% O/ n6 h
""""属性只能做为参数,所有的操作只能针对标签""", {8 r: Z/ }  {4 M* Z
( U9 z, K6 b! W$ z6 ?
etree方法:
% Z- k% C! U' u/ D% V导入库文件:7 R: d7 z, F' H4 l5 S7 A6 Z/ D

4 J  w9 g. |! Q3 y1 Sfrom lxml import etree
# J$ C6 O7 B2 e. ^' i+ h14 }& s' K2 y/ F! \( l( a' s6 ?5 u
解析得到的response对象;; L9 o4 N& P+ j8 s& x: K# E3 k

/ E! E0 l; N6 C# 设置response的字符集
% l* ^  T2 o& ihtml = req.content.decode('utf-8')2 x& n- T# `- T! V3 r
# 解析对象4 }. v3 l; N5 m/ i+ r4 y0 E
html = etree.HTML(html,parser=etree.HTMLParser(encoding='utf-8'))
( H/ c. M) O9 J- y; ^% w
  @* T7 a2 l9 E常用的方法:
, m/ Z3 g. m, v, |* X1 x
- c+ ~0 M# E/ W. R0 p/ U4 ~) ^6 o+ M( _8 k0 J3 G0 @1 x# z
# 定位head节点(元素)( N. ?! |, G+ L  ]5 t3 l# H( r, O" I' B9 `
result1 = html.xpath('head')
6 s1 Z) w% _8 }9 Sprint(result1)2 P( ~) U  s: z4 @: Z
# 定位title节点3 f3 t2 \! B# O; K. B& o" n
result2 = html.xpath('/html/head/title')! `$ G% v4 b3 r  K$ L! `
print(result2)
; E& E0 o5 @# }! S) X# 搜索节点  title节点% [( A+ P) F: B8 Z/ B. N+ B
result3 = html.xpath('//title')8 P) Y$ i4 M6 ]& a: P
print(result3)+ {% A1 M/ y* p- T- v6 _2 Z
# 搜索title内容  text()得到文本信息
0 j/ s% F0 ?* }6 l' M  D) Gresult4 = html.xpath("//title/text()")* m9 p1 [4 P: _( I  a  g. d. k/ ^$ e% }
print(result4)
; s2 K4 b+ U8 O; o9 g# t( M# 搜索div节点9 e" n7 b! j9 v5 n; u6 _) [
result5 = html.xpath('//div'); I0 Y3 i/ V! Z
print(result5)
+ G* ?. B5 J  E0 ]: n' E# 搜索div节点 并用class属性定位/ m9 e. M! E; v( u/ E0 j# v( ~
result6 = html.xpath('//div[@class="news"]')! C  _  s6 c; K# Q& W5 W- |7 s: Q
print(result6)- V4 |- K' @) [! X. z# [3 V- K$ m
# 搜索div节点 id属性定位5 t6 q: |9 E* @  g4 c+ d: E3 X
result7 = html.xpath('//div[@id="news"]')( C1 }9 m( F$ z" v/ }. Z/ F
print(result7)
! G2 \- k$ G5 }  I# i# 获取列表span信息9 |8 m) T. q- Z, P7 {+ x
text = html.xpath('//div[@class="news"]/a/span/text()')
! s# }1 B% }9 Q- w! ~4 K' [  Oprint(text)' t6 |; M9 Z' l( B

7 O2 R! C1 [, a% I

g、通过上一步我们得到自己需要的数据后,下一步就是将我们得到的数据进行保存
0 M: D4 c6 w6 M保存的方式有很多种:
" l# {8 {6 o5 q' l* ?7 ~: l; l" F1、保存至文件* \9 u/ y  V4 E
csv、json、text4 V* i  j, M( S! S8 T( l+ V
2、保存至数据库
# {. ~+ X# G$ s4 E5 E6 p3 NMySql、MongoDB、Redis 等 (目前主流的为以上列举的三种数据库)

关于数据存储后面再做详细介绍+ R' H8 k+ t! k. m% D7 W3 {
2 x8 Z0 e( q  M8 {

  H  S6 a3 n9 J————————————————; [, g8 ]  |( X+ e
版权声明:本文为CSDN博主「royallucky」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
# }' w) `/ p/ k3 T4 _. b% J原文链接:https://blog.csdn.net/royallucky/article/details/105930473
0 D. _! `3 t) W) ~/ m1 S! V  y  g, e

# y' d! p. i7 V! L/ t
作者: 建模小白12138    时间: 2020-5-5 20:43
感谢楼主,,,,,,,,,,,,,,。
$ w* l7 D  d6 K




欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) Powered by Discuz! X2.5