QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 3792|回复: 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

    / Z. X/ L# Q1 E& \

    ) I2 s/ p' S. |6 f  r* W

    # {9 \+ `5 u* ^8 Q8 C
    手把手带你5分钟搞定爬虫(聚焦爬虫)

    3 H6 O: d9 s+ |0 y; r' R1 h, }6 b
    , p6 U# O! }) `6 ~% d9 c, B- {爬虫的原理/ K1 s! G/ y3 c% v1 G+ x9 ~
      R) y2 n6 a3 u( E! W% m- f2 S* r
    对于很多刚入门的小伙伴来说,了解爬虫的工作原理是非常重要的。只有当你了解了它的原理,你才能结合实际情况写出对应的爬虫。下面我将以通俗的语言方式来介绍爬虫
    ( x7 a7 P" t( @$ G把互联网比作一张巨大的网,那爬虫就是这张网上面的一只小蜘蛛,在互联网上面有很多的数据,各种各样的数据,我们可以把这些数据比作是被网粘住的小昆虫等。爬虫的作用就是去找到自己喜欢的口味,然后把它带回家,可以储存起来,也可以马上享受美味; O7 H( r" ^* v
    所以说爬虫分为三部曲:. g5 ~8 Y5 U8 N1 t- f8 i
    1、明确你自己喜欢什么口味(制定需求,明确你需要的数据类型)
    * z' K' G2 ?( L2、去找到你喜欢的食物的位置(得到目标地址)
    $ l3 N, e  @% {+ w1 I* P4 s# f( l3、把食物搬回家去(解析网址,获取数据,存储数据)
    # ^1 c; o7 [9 o, w: l它的整个流程就是:(简单的通过request请求获取数据并解析获取数据。以下都是固定化格式,可以照搬)+ I, O; [. `1 Y: i
    a、导入需要的库 requests
    $ x9 `) Y5 P8 w5 z! @! ]% B) O( D* I- n% T: W
    import requests
    0 U% ~: l% e  E* I7 j" y1
    ( [: x" ~. a! s6 Db、明确你要获取数据的网址(这里以百度网站为例)
    ' K( u: H+ t1 P, Z+ }" M) f; n2 J4 f0 H! s
    url = 'http://www.baidu.com'' L& V# c- F$ R' o
    1
    1 S% L' g5 Q& \c、创建请求
    : ]! Q# b1 S, L; J8 ]* ]7 t7 S: j2 @
    response =  requests.get(url)$ e, [  c2 `! ]
    15 [& X5 |9 f+ }3 w" y" V/ w
    d、测试请求是否成功(在实际应用中用的比较少,正常情况都是可以请求成功的,网站对于访问外部信息的爬虫是不会做出限制的)7 V. s7 e5 m; y: W+ N9 P" `
    ; ]# t! [8 ]8 |6 P' o' \
    print("状态码:",response.status_code)
    1 u4 B0 {0 u: C# f% O1
    ) Z* t0 c5 k7 D' \( `( u- E当状态码为“200”时表示请求成功;如果不是“200”,很大可能就是你的目标url写错了,核对一下url% R; g7 I$ t$ d& s: T, K8 m* h% c
    e、得到网页源码# O. h) I% O, m6 I; X" ]) @
    2 i7 b3 P: Q. M
    print("内容:",response.text)$ V% L7 _! d5 ?+ [5 |/ c
    1
    + x# P3 y% X9 s" V1 B$ _# Zresponse.content是response.text的二进制形式
    2 }6 ~0 P: A( J. p1 c
    " Y8 n, r- N( C: R; k7 P9 x* r) G至此,一个简单的爬虫请求就算是完成了。- f* W! I! A" `/ I7 a! d/ w
    当我们请求目标url并获取到response后,就需要进行下一步:解析网址并获取数据
    % y3 ~) `6 x0 _2 M  |, Y( Ef、解析网址* X. T# n& {0 P$ i% e7 X2 I* ?, W
    刚开始学习阶段,我们最常用的两种方法,一种是BeautifulSoup,一种是etree。其中BeautifulSoup是最常用的。以下将对两种方法分别进行介绍 (以下方法均为测试用例,实际当中应结合自己的实际情况选择应用)
    8 D/ w" H0 R1 s0 Z3 _& mBeautifulSoup:0 P+ x% M, f2 S
    首先导入需要的库文件:
    . B! x, o! Q' @* e; @! Z% k& v- U: U2 w
    from bs4 import BeautifulSoup
    # k& J9 U5 A; a1
    ; y" n; Q9 h2 f, {# o然后对上面请求得到的response进行解析:8 D$ e; c  N7 s7 U% y1 D; w1 F' C

    7 e' M; k/ V, ]2 V/ @% W4 Y1 ~html = respone.content.decode('utf-8')/ l! }$ c) m9 K& I
    soup = BeautifulSoup(html, 'lxml')
    9 a6 P, p8 i: j( X$ k; w; c' G17 V  ?* u1 B" p- S4 n$ ?7 b, `
    2+ n+ Z0 f/ _' L6 @9 M- U
    以下是BeautifulSoup中比较常见的方法,有兴趣的朋友可以去一一测试:
    $ a& V# X+ g. h; I* g: a3 _, z# 获取head标签0 S+ i: R! f4 f+ A$ }; J
    print('head标签内容', soup.head)
    / g% S; n; @: O* S% }5 E9 o# 获取title标签
    / B* y5 }2 |- xprint('head标签内容', soup.title)
    9 }' H9 A/ ^8 M- D0 [9 r2 T6 a# 获取body里面的img内容
    - t/ h6 F/ N- f# 通过点号的方式只能获取 下属第一个标签(即获取soup下面第一个body里的第一个a标签的第一个img标签)/ }2 F7 H( F6 a5 x4 N/ ^
    print(soup.body.a.img)   
    1 Q3 k+ a5 [; X1 E# 获取所有的img标签  使用find_all()搜索整个soup对象
    8 j8 S( w( s( _7 o1 `; c% c3 E, I4 bprint("获取所有的img标签", soup.find_all('img'))
    ( ^- w4 i. d* P; u  u# 获取标签中的属性src地址; z9 O: v! \: R& M" a& v% _
    print("获取标签中的属性src地址:", soup.img['src'])      # 注意:英文点号都只能获取第一个值/ L( V" m* ?& P0 v2 k' D

    4 {9 e# [- `. s; n% q* z: h8 K* T9 u4 U
    # 获取soup的name
    ( ?' A" W7 \( h3 K* Dprint("获取soup的name:",soup.name)
    : C) c- _, _- }( j' d6 V; z+ r# 获取a标签名
    + a/ J5 U$ P7 T1 a* \print("a标签名字:",soup.a.name); ^6 I. B/ a3 K
    tag = soup.a
    ' @9 O9 T& X; n. ?9 u3 ~4 Wprint(tag)
    + O/ C3 n) I3 m2 e# 修改操作  a标签改为b标签
    / ^9 X! V" o, o. P) Z$ @tag.name = 'b'   # 赋值后<a> </a>变为<b> </b>$ M/ [5 Q1 \2 k) ?1 k; @, F7 n
    # 输出修改后的内容
    9 @5 u4 `  X( D: }print("输出修改后的内容:",tag)) N: R9 o( ?" ~. ~5 {8 r
    # 获取全部的属性 attrs
    9 C) O) J& N" N' M9 K4 Aprint("tag对象的全部属性:",tag.attrs)   # 只能得到当前标签的属性(不包含下属标签)( a+ S0 x0 E. j, u
    $ N& x8 P( ]+ L
    # 获取属性的class的值   根据键取值
    4 y- {: t5 z" i1 S+ d2 Cprint("获取属性的class的值:",tag["class"])
      M/ h* t4 M' U6 t; L$ e8 h/ }. B9 ~/ t- f- B

      u- Z) ?# t& N$ J' u% A
    7 ~& S. u+ r* {4 y! T# i. |  k6 x- `1 b2 z, u( [$ n+ }
    """针对获取的标签属性可以进行增删改查"""0 q: L/ I1 x0 F9 v  C; `" L
    # 修改
    4 Q6 S( a! O, G/ P3 Ztag["class"] = "Logo"* j+ u: i- X( k
    print("tag对象的全部属性:",tag.attrs)
    0 _/ ]: b( [0 X9 d5 j( M& J  D$ [# 输出属性
      U3 G* I; L+ L) l5 T7 M9 Rprint("获取属性的class的值:",tag["class"])
    6 H5 k: N1 @# j1 U! \# 新增  属性id  赋值logo1 X4 k9 ]5 V5 B) {# t/ c4 Q' b( R
    tag['id'] = 'logo'2 ~. Q) E- D! D
    print("tag对象的全部属性:",tag.attrs)( B' ]6 g, V* _% a/ Y3 m$ N
    # 删除属性
    & \' N/ s* }& B! D; v% T. zdel tag['class']0 e$ U6 b1 u1 D/ V6 c! D" h
    print("tag对象的全部属性:",tag.attrs)( u  S$ c7 v$ Z: y6 [+ ?3 b
    2 z6 r1 H/ Y8 w. U& u
    1 u$ _1 C2 z1 ?, {

    0 \8 s0 U. V- D' t"""针对内容操作  (只针对标签,对属性无效)"""
    1 ^) U" Q1 N) t4 x( ]- P# 获取title标签内容6 f6 A6 A; F" P
    tag = soup.title3 P  u0 A2 s( |% A5 S# g
    # 获取title字符串
    ! X9 @5 C) @0 ^7 ~1 eprint("tag对象所包含的字符串:", tag.string)8 q% V7 \3 x; f* Z1 m9 e7 {
    print("类型:", type(tag.string))
    $ ?2 C9 m- ?. l3 S9 m  V) h# 替换内容  l2 w# F1 M* y  s- `+ |, t, j( f
    tag.string.replace_with("你好")
    # a1 Y5 r( O  \1 Hprint(tag.string)
    ) w& U' |7 S! T/ Z5 G( s( w# <!-- 学科建设 -->
    / K# O* t% O" D, R3 u* a* Z3 O# 获取注释文本内容
    1 @  F6 H+ \. c2 l# R9 J! t; W$ `markup = '<b><!-- 学科建设 --></c>'
    9 v! J) ~4 \& M2 V# P$ L1 Gsoup_comment = BeautifulSoup(markup, 'lxml')* A7 G% }' Z; ?% n! Q% o* i
    comment = soup_comment.b.string                    # 以markup第一个标签作为关键进行搜索; q1 ?5 m; l1 j+ p$ r1 b/ i3 M
    print("获取注释文本内容:", comment)0 F8 ?: }3 [* X" L; g3 O5 u
    # get_text()5 x7 j  i' A% R7 i4 A
    print("title的全部节点:",soup.find_all("title"))
    4 D" _+ H* C7 q% Nprint("title的内容:",soup.title.get_text())7 L  C/ l9 |1 v7 I
    """查找ul元素标签"""# j0 }- p1 Z- F5 K6 U
    # class是关键名,匹配时后面必须加下划线_, P( i# O# D! \: F+ }
    # tag = soup.find_all("ul", class_='menu')  # 按照css类名完全匹配' P, m5 C& U+ o1 h
    # print(tag)
    9 A/ O4 S. {. w7 ctag = soup.find_all("ul", id='menu')  # 按照css类名完全匹配! o3 T6 |$ A* Z$ Z- Q1 N
    print(tag)
    + B: ^( H# O- o- w' |  M# 查找名称为a元素的标签内容( A7 l! [3 E* ]$ t- }
    taga = soup.find_all('a')
    8 ~. u2 G" ~" h# Z. v# r2 N% [* lfor tag in taga:5 w( ~! Z' V3 h, C/ t
        print("查找名称为a元素的标签内容:", tag.string), Y9 N8 {0 P8 r. d; I
    # get 获取属性信息  获取整个页面的img标签图片和src属性值
    4 b$ x# ]. ?; U8 X6 C* ctagings = soup.find_all('img')
    * l4 h4 T$ E. V" L0 J+ R% w6 Tprint(tagings)
    " \$ o$ E7 i. {, P+ z) k( K3 t# 循环输出图片地址
    ; z* k9 l1 v  V4 @& l6 Efor imgsrc in tagings:
    ( }( k/ V5 T$ w/ }: A    print(url+imgsrc.get('src'))
    6 j" z% `( ~: ?5 o3 f. }4 w" ^% }& z  l5 `
    """"属性只能做为参数,所有的操作只能针对标签"""
    , \) n. `+ V4 v3 N
    0 }5 V! b( o# Detree方法:
    * H. R+ }7 ?9 O! J9 ^- E, E2 [: d导入库文件:2 Q1 N3 u- I- b" g& @

    , f4 o9 J4 u/ w- Lfrom lxml import etree
      X, G4 S0 s  i: x+ M# m1
    3 e' g5 s0 u- g- O9 }  I解析得到的response对象;+ D/ |' S/ O2 Z2 s0 |$ |

    9 d2 _9 B2 R$ n3 s$ p# 设置response的字符集
    0 T" [+ x9 {; G1 rhtml = req.content.decode('utf-8')
    , V) ]  Q: g3 J3 O9 N2 i# 解析对象
    % y* v- ]. z+ L3 Bhtml = etree.HTML(html,parser=etree.HTMLParser(encoding='utf-8'))
    0 D8 T6 }7 e- a' i/ d
    3 n5 J  e+ e: K6 ]$ G/ e3 D3 ]: g常用的方法:
    ) l6 J/ q% w" T" [# y" F6 S& Q; ~
    ) q. }, |1 Y2 `, P1 i5 j
    3 p" W) B1 ]" F! c1 x4 A# 定位head节点(元素)( A' d% a2 L6 v3 A! c' y
    result1 = html.xpath('head')
    * B1 c  B, y% Q: x# g6 qprint(result1)
    ) Y0 F1 {' B7 H; P, n7 P# 定位title节点8 A' k' c% c5 e* I- G6 S
    result2 = html.xpath('/html/head/title')# }9 z5 `' G. \2 z- T
    print(result2)
    0 f) U& x  p0 A, G8 z# 搜索节点  title节点* E+ w. C3 y' }3 d
    result3 = html.xpath('//title')
    , o/ B8 O% i& r3 I3 X/ nprint(result3)9 T% u5 I# ?- I* t6 l; t& O+ W  a; R
    # 搜索title内容  text()得到文本信息
    3 Y; @# G# Q; H- Dresult4 = html.xpath("//title/text()")
    - o7 k: k2 x3 Fprint(result4)
    7 _# v) k, d* t* u# 搜索div节点5 T5 ?( A& V4 g6 n5 o  {
    result5 = html.xpath('//div')
      \) ?" n6 {% ]* ?, X' N$ w* Wprint(result5)3 o" o/ @! u% D2 u9 y
    # 搜索div节点 并用class属性定位: x! v" C6 Y& u+ n
    result6 = html.xpath('//div[@class="news"]')7 M3 m& Q$ @) V
    print(result6)
    1 ~* D; |" G, n+ [9 L- J7 Y# 搜索div节点 id属性定位
    * L' i# a# }9 V1 [result7 = html.xpath('//div[@id="news"]'): o2 L& H: X# j( q& ?* j6 ~
    print(result7)
    5 C; C. b. @. x* v5 c1 `! D' n9 t- z# 获取列表span信息/ I5 [$ v. R6 n7 D& M
    text = html.xpath('//div[@class="news"]/a/span/text()')
    + x8 E7 |1 }% `% T  wprint(text)
    ; d9 {+ W. w; R) N; L/ d4 m0 R" k; _9 g. T

    g、通过上一步我们得到自己需要的数据后,下一步就是将我们得到的数据进行保存! i7 y& Q1 @7 X  P; a, w; ]$ _. _
    保存的方式有很多种:! l& L8 C( M" P% e9 `3 {. v
    1、保存至文件
    $ r* T3 o6 b7 @4 `3 bcsv、json、text
    , C3 J6 g7 e6 F2、保存至数据库
    9 [; h, q" _0 w, R3 f1 W( w# B2 lMySql、MongoDB、Redis 等 (目前主流的为以上列举的三种数据库)

    关于数据存储后面再做详细介绍
    # q  p4 R1 c6 O+ a. }9 ^
    - G# F! T3 e8 |! ?( k
    - U. k: a3 |/ h————————————————
    " i- _7 E  I( N$ e版权声明:本文为CSDN博主「royallucky」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。0 g- g: q; ?# Z$ v
    原文链接:https://blog.csdn.net/royallucky/article/details/105930473$ [' b5 d* {5 R2 W9 ]- L) r
    $ z( x9 q. l3 v1 m3 u
    4 O3 }( O" s; V! Y
    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 10:35 , Processed in 2.183139 second(s), 56 queries .

    回顶部