QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 3790|回复: 1
打印 上一主题 下一主题

手把手带你5分钟搞定爬虫(聚焦爬虫)

[复制链接]
字体大小: 正常 放大
杨利霞        

5273

主题

82

听众

17万

积分

  • TA的每日心情
    开心
    2021-8-11 17:59
  • 签到天数: 17 天

    [LV.4]偶尔看看III

    网络挑战赛参赛者

    网络挑战赛参赛者

    自我介绍
    本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。

    群组: 2018美赛大象算法课程

    群组: 2018美赛护航培训课程

    群组: 2019年 数学中国站长建

    群组: 2019年数据分析师课程

    群组: 2018年大象老师国赛优

    跳转到指定楼层
    1#
    发表于 2020-5-5 14:21 |只看该作者 |倒序浏览
    |招呼Ta 关注Ta
    : T. q' r. O, N) w4 o3 b; Z& K
    % V, O! H: \2 ]# A

    ! W: p5 N$ ]/ S- v
    手把手带你5分钟搞定爬虫(聚焦爬虫)
    1 w5 E% [) G3 K! @. P7 L

    2 o1 G7 d5 `( h4 v, U, Z爬虫的原理
    . T5 e2 l% T6 o+ D8 w0 D8 O. |, C  W  }5 P! ^2 O2 `3 ?; x% N$ ?; B
    对于很多刚入门的小伙伴来说,了解爬虫的工作原理是非常重要的。只有当你了解了它的原理,你才能结合实际情况写出对应的爬虫。下面我将以通俗的语言方式来介绍爬虫
      ?9 ~$ O4 A: p+ h6 P$ f1 c3 e把互联网比作一张巨大的网,那爬虫就是这张网上面的一只小蜘蛛,在互联网上面有很多的数据,各种各样的数据,我们可以把这些数据比作是被网粘住的小昆虫等。爬虫的作用就是去找到自己喜欢的口味,然后把它带回家,可以储存起来,也可以马上享受美味
    ! t) b9 L9 ~: n! g所以说爬虫分为三部曲:$ @0 R! @, L- r
    1、明确你自己喜欢什么口味(制定需求,明确你需要的数据类型)4 \6 D' |+ z# f; n7 C
    2、去找到你喜欢的食物的位置(得到目标地址)
    6 r6 [# j, z) G' l4 y3、把食物搬回家去(解析网址,获取数据,存储数据)0 ~; ~, o+ [( N4 i! O' c
    它的整个流程就是:(简单的通过request请求获取数据并解析获取数据。以下都是固定化格式,可以照搬); p9 b# Z* E/ y2 o
    a、导入需要的库 requests
    0 |* j1 d7 i$ I! P. l, e; z
    # E# K; u8 Q( w# W& D$ j1 Pimport requests3 w$ M+ Z/ y4 U  k8 F
    1
      u' j2 P7 s& |& V" W4 Lb、明确你要获取数据的网址(这里以百度网站为例)) |% A7 t- @( J: W4 o

    ) n- e/ B# s) n* Turl = 'http://www.baidu.com'' _3 G/ k: H6 f4 b: l) M
    1
    2 L1 \& P4 A7 ]. Y: J) ]c、创建请求" r2 F+ A, M; \

    . u( R+ u, ?) z4 k5 hresponse =  requests.get(url)
    ' ?8 s: b6 {3 X; Z/ C1. D( e1 t* @; k) Z" K
    d、测试请求是否成功(在实际应用中用的比较少,正常情况都是可以请求成功的,网站对于访问外部信息的爬虫是不会做出限制的)
    / e) }& ^+ Y6 {) \# L3 I$ X  c% g0 q2 C. {4 n7 k3 k
    print("状态码:",response.status_code)
    2 E' T! [4 r- f- |, t* H- _) R1; j# ~+ |; n% e5 j5 A+ B3 M
    当状态码为“200”时表示请求成功;如果不是“200”,很大可能就是你的目标url写错了,核对一下url
    * t+ T/ H9 X  n( @5 k& E9 ve、得到网页源码& K, ], Q, e0 {8 h; `
    8 }* A7 x2 y8 d1 R$ k& J
    print("内容:",response.text)* x7 L  H8 E5 l
    1: N; S" |4 X; h2 P# m! S6 i! Q
    response.content是response.text的二进制形式
    - N$ P& }# F  k" s: U+ ]8 g8 @& _6 v5 u
    至此,一个简单的爬虫请求就算是完成了。" Y$ f7 _7 Q" ^
    当我们请求目标url并获取到response后,就需要进行下一步:解析网址并获取数据% I( o, m4 a5 J5 j0 z
    f、解析网址& T; C1 I0 L; U, E& h
    刚开始学习阶段,我们最常用的两种方法,一种是BeautifulSoup,一种是etree。其中BeautifulSoup是最常用的。以下将对两种方法分别进行介绍 (以下方法均为测试用例,实际当中应结合自己的实际情况选择应用)4 g5 r- t% B9 R3 K
    BeautifulSoup:
    ) z' w. A" W+ C( w# w  I+ x& _; I! m) A首先导入需要的库文件:
    ! _2 n( c) l' ?  m9 O" b& p! I
    ( H6 Y7 j- ]; c- E2 ^, ?! Yfrom bs4 import BeautifulSoup
    $ S: E6 Y' G% A' ~) t4 ^+ S  f6 v1
    + A# Q9 C( P* U1 W; B, F然后对上面请求得到的response进行解析:0 L, m. _* `7 M! _

    $ t2 r: ^% l4 H$ ?" _/ Chtml = respone.content.decode('utf-8')
    , y" Y0 X1 z9 H3 qsoup = BeautifulSoup(html, 'lxml')
    ! w' L1 {5 r5 |- U1 ?1 |( C1
    ' C4 R( }* c- H% l: T) F; o2
    " u: Z' z4 [% |0 V& ~' w5 j以下是BeautifulSoup中比较常见的方法,有兴趣的朋友可以去一一测试:5 M# V% ^7 g4 u( A% S9 H! V5 f8 R
    # 获取head标签
    0 D, q. M' y; M3 \  G! `1 Y" Hprint('head标签内容', soup.head)
    3 k1 r) _# l8 ]4 V5 V. g6 ^/ X# 获取title标签
    $ K9 A/ n! O% k* `- Dprint('head标签内容', soup.title)
    ; J; Y" Z. ~9 f1 f# l6 j! `# 获取body里面的img内容
    9 }* u& P3 E' f! r$ y9 K5 n# 通过点号的方式只能获取 下属第一个标签(即获取soup下面第一个body里的第一个a标签的第一个img标签)* A5 y% N, `+ l0 N& ]/ }; q
    print(soup.body.a.img)   
    4 T' d# Y3 {9 a! y) Y2 ]# 获取所有的img标签  使用find_all()搜索整个soup对象% X6 P# {2 H# S5 U- ?7 C
    print("获取所有的img标签", soup.find_all('img'))( C  T7 i# }: l' q0 F8 L! {' g" [
    # 获取标签中的属性src地址0 @  o: n" X$ O3 l% \( g
    print("获取标签中的属性src地址:", soup.img['src'])      # 注意:英文点号都只能获取第一个值  ]  l2 y+ Y* p: [5 A" D+ N

    $ C  i! R& i# N7 u
      p- ?$ C# _7 t* F7 R" s4 w# 获取soup的name' h- Y* v5 S2 ?0 F+ f2 L5 v
    print("获取soup的name:",soup.name)
    1 P3 ?- N, A1 u" d  ~- m# 获取a标签名+ a: ^' p. C* m% a1 G& g1 g
    print("a标签名字:",soup.a.name)$ c  C) F* h- [/ C
    tag = soup.a0 c$ k4 |$ e5 ?$ S
    print(tag). U8 c" m  P( X* s6 f' S1 @
    # 修改操作  a标签改为b标签
    & X" r" q2 g( E. a! ltag.name = 'b'   # 赋值后<a> </a>变为<b> </b>+ D1 e2 y. p, g% {  d; C9 ^1 ^
    # 输出修改后的内容) u4 f4 ?! @# ~6 P  T' u; k
    print("输出修改后的内容:",tag)& K( @7 J) W! v7 C3 J& y/ d
    # 获取全部的属性 attrs
    # }) ~( h5 g4 m6 E$ {print("tag对象的全部属性:",tag.attrs)   # 只能得到当前标签的属性(不包含下属标签)# k% X) a; |& L8 O% Y

    % ?9 A+ B: z% e/ d- J- i  \6 G/ t# 获取属性的class的值   根据键取值# m, E& |# g4 B# P) |
    print("获取属性的class的值:",tag["class"])
    $ q! [4 n4 a3 t' ]6 ^4 v2 m# h
    # [& [8 P; Q1 X+ F% O1 d5 [4 d

    5 J3 S8 H0 f5 ]( n6 V- L8 [& @8 p# C1 n& i. B' T
    """针对获取的标签属性可以进行增删改查"""
    2 |2 x4 @$ _: p" m" U6 S+ ~5 `# 修改" @. e# l4 f' M* z) m& N% I7 ?' h
    tag["class"] = "Logo") _* X, n) x6 e$ L' U3 ?
    print("tag对象的全部属性:",tag.attrs)
    6 O; g+ V7 n. I  C( [3 L# 输出属性5 J$ W+ P6 M0 E" _
    print("获取属性的class的值:",tag["class"])
    / O: a& c) ]# G. M' J% _( }# 新增  属性id  赋值logo
    : c. q2 }) v' Z" d) P8 r6 _) Etag['id'] = 'logo'
    $ Z& D% a4 W+ D7 e6 \& Eprint("tag对象的全部属性:",tag.attrs)
    8 ^6 ?1 @/ q6 B8 l2 Q# 删除属性/ E8 V5 t# N8 ^. Z6 v+ o9 N: r
    del tag['class']
    6 b( A' C" Q: Q# J* B' D+ `print("tag对象的全部属性:",tag.attrs)" ~1 }/ H8 b7 i- \8 K4 C

    ) o1 p7 s) o& \8 u
    4 [: }' }' `& j$ |3 M9 X. O/ m
    """针对内容操作  (只针对标签,对属性无效)"""0 Z* @+ ?: k0 p
    # 获取title标签内容$ N3 F- Q: a, d# l
    tag = soup.title
    2 }4 E9 P8 x4 ^5 E  q# 获取title字符串
    5 l7 ~9 ?: [: p" b5 t! zprint("tag对象所包含的字符串:", tag.string)
    2 f( p% B; h- Qprint("类型:", type(tag.string))# j, g, X1 ~- e6 G0 S9 i3 C
    # 替换内容4 b! p% T7 q# x+ ?9 C
    tag.string.replace_with("你好")9 v1 s. D% u9 ?' @/ _
    print(tag.string)
    1 H) `% T3 J7 U5 ^# <!-- 学科建设 -->3 j1 @. e& Y8 e5 y4 A8 r
    # 获取注释文本内容0 u7 M" O/ e' D# v/ R
    markup = '<b><!-- 学科建设 --></c>'
    7 C+ j' k+ l) O$ a- Q6 Y+ nsoup_comment = BeautifulSoup(markup, 'lxml')
    8 a2 U" Z7 H1 D& ~! v1 rcomment = soup_comment.b.string                    # 以markup第一个标签作为关键进行搜索- m+ C$ }" `# `# e5 Z! [
    print("获取注释文本内容:", comment)
    + t# g& X9 a6 a! Z) o5 E# get_text()
    $ w+ o  L* P( o3 n+ [print("title的全部节点:",soup.find_all("title"))
    6 X* _7 J$ D5 y$ Aprint("title的内容:",soup.title.get_text())
    0 `$ Y6 T, y( t' ~& v0 l, C- a"""查找ul元素标签"""; T, ^8 n( m8 L4 d% y6 t
    # class是关键名,匹配时后面必须加下划线_
    . Q' S: @  i/ q) P/ ~7 W+ n# tag = soup.find_all("ul", class_='menu')  # 按照css类名完全匹配% `0 Y  z. d$ b- n- K# d
    # print(tag)1 i# g( w* F4 T" X, F" ^
    tag = soup.find_all("ul", id='menu')  # 按照css类名完全匹配
    ' r* y$ }( @) aprint(tag)" b% u8 g  [# z( b
    # 查找名称为a元素的标签内容: O$ l! _& r0 h3 A3 U
    taga = soup.find_all('a')% n4 k! j: A# m! b/ C
    for tag in taga:
    4 Q# G8 S4 i7 R, u6 \1 R) t    print("查找名称为a元素的标签内容:", tag.string)
    ; M4 e/ o; \  V1 f# get 获取属性信息  获取整个页面的img标签图片和src属性值
    6 Z$ w1 Q# K; Y# V% ptagings = soup.find_all('img')# @3 E" x6 X. K- g4 f
    print(tagings)
    0 o) v- K$ v  s, Z5 E# 循环输出图片地址
    5 Q2 s3 m1 Q9 o. ?" Sfor imgsrc in tagings:. q0 t, p  l* o' m- }3 o1 v5 F
        print(url+imgsrc.get('src'))
    . f* P+ W  g7 |; `" G
    7 B2 q# u+ ~. `! b, s0 M6 ~' e""""属性只能做为参数,所有的操作只能针对标签"""
    ! h5 e0 {# b& O8 y
    0 ~9 m$ t/ L3 l9 u* F3 cetree方法:
    $ K* M* Q. u1 M) ]8 F导入库文件:
    4 `- T# M2 ~: B6 a# o' C$ V
    ! ]- ]+ K, V  |' c4 r( Tfrom lxml import etree+ f: c  n; P# p; d4 |5 e$ U
    1
    & }$ o6 I) r. _解析得到的response对象;8 q* ^" ?  L7 t5 ]
    / ]" V+ j6 H' U1 ^
    # 设置response的字符集  v% U. ?- q3 l6 J
    html = req.content.decode('utf-8')
    4 @- o% |' R7 T+ [- n6 {4 y  L4 O1 b( B# 解析对象: Q2 U# }' O# F' c+ n/ c# c. Q
    html = etree.HTML(html,parser=etree.HTMLParser(encoding='utf-8'))
    ; X( W9 E0 F  \* z% z& q6 s3 v
    + Z" \( r! o; _6 @+ a常用的方法:' e: q% X5 c' r. L' D$ ]7 T& Q( l
    5 z9 U; o0 e$ _  q9 |
    8 j& n9 l9 ?+ t& g4 v6 E1 C
    # 定位head节点(元素)
      J4 _$ I) S$ j9 K: g4 b2 W; wresult1 = html.xpath('head')4 P5 @6 M: M- [6 c1 B
    print(result1)% o  J) e: W4 `3 w: v4 R  r' v& ?
    # 定位title节点# `; m+ Z6 ?) E+ R: n
    result2 = html.xpath('/html/head/title')
    / ~9 h. y* v# J7 p  `print(result2)
    7 v3 {$ M) a  ]7 M" V0 W# 搜索节点  title节点! f5 j0 g  o: D
    result3 = html.xpath('//title')
    $ D# ~3 Y5 H: ~print(result3)
    # \2 E/ X+ c* k, u5 F# 搜索title内容  text()得到文本信息: Q: ]+ \7 Y8 E2 l
    result4 = html.xpath("//title/text()")
    * q) N5 ^* i, i; }- \' yprint(result4)! a' ~* Y: D# R4 e
    # 搜索div节点
    ! V  m1 A3 |7 c6 ]! ^! W, mresult5 = html.xpath('//div')' o* ]" R+ F. j/ y! ^% `# w
    print(result5)
    7 k8 m0 p6 t0 n- s- P0 L# 搜索div节点 并用class属性定位
      V/ f) s- c; j( s2 Vresult6 = html.xpath('//div[@class="news"]')
    % W% A6 y7 F- z  hprint(result6)) }) @9 |# |: S0 o. U
    # 搜索div节点 id属性定位
    9 g' I+ [" h4 h0 b( Q7 K7 Eresult7 = html.xpath('//div[@id="news"]')
    " L( g9 y5 D! g% [  C' tprint(result7)8 m( a7 S. y  M
    # 获取列表span信息% T/ q% d. }/ l6 m. V; e$ o
    text = html.xpath('//div[@class="news"]/a/span/text()')# q, l3 q" S: ~1 r+ J9 t
    print(text); N$ H& v' }9 ]6 g& o

    , H6 h7 ^4 s# d" r1 ~

    g、通过上一步我们得到自己需要的数据后,下一步就是将我们得到的数据进行保存
    / _7 F, U. k1 R$ X& x" t# a保存的方式有很多种:
    , Y; U" X$ f& x# ?, ^* d1、保存至文件/ U. x" |5 ~# x! F% w
    csv、json、text
    0 H7 a6 S% c* u+ @8 F3 ^) _" c2、保存至数据库  G5 u, u  Z4 t" B0 {: Z
    MySql、MongoDB、Redis 等 (目前主流的为以上列举的三种数据库)

    关于数据存储后面再做详细介绍
    : s, ?: I8 b2 h2 ?6 H  f1 D) {
    ; F/ M5 P# Z& C. I2 p* S5 i* ^
    * f( ^0 W0 D: p  A( B( \————————————————
    + R$ q; f3 i; n+ k版权声明:本文为CSDN博主「royallucky」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。9 q, L% f$ e7 D1 e
    原文链接:https://blog.csdn.net/royallucky/article/details/105930473
    9 D6 Y: [5 D- _( t9 w4 R: c& d* k; c+ }

    * y# m, p, u" n* R, Y5 X
    zan
    转播转播0 分享淘帖0 分享分享0 收藏收藏0 支持支持0 反对反对0 微信微信

    2

    主题

    5

    听众

    338

    积分

    升级  12.67%

  • TA的每日心情
    奋斗
    2021-7-23 00:47
  • 签到天数: 124 天

    [LV.7]常住居民III

    自我介绍
    Hello world!

    群组: 2013电工杯A题讨论群组

    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 注册地址

    qq
    收缩
    • 电话咨询

    • 04714969085
    fastpost

    关于我们| 联系我们| 诚征英才| 对外合作| 产品服务| QQ

    手机版|Archiver| |繁體中文 手机客户端  

    蒙公网安备 15010502000194号

    Powered by Discuz! X2.5   © 2001-2013 数学建模网-数学中国 ( 蒙ICP备14002410号-3 蒙BBS备-0002号 )     论坛法律顾问:王兆丰

    GMT+8, 2026-10-2 09:40 , Processed in 2.451185 second(s), 56 queries .

    回顶部