QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 3350|回复: 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
    . b/ J' G7 V! b/ Z
    ; c& A6 k2 ^( N5 }
    ( W! e; z  K2 g/ _) ?4 ^, N
    手把手带你5分钟搞定爬虫(聚焦爬虫)
    6 `* v  u8 v# P& z. K
    " k$ x0 W& p7 Q3 @7 ?
    爬虫的原理0 Y- u: t* F; P4 `8 S8 D8 @# J
    8 Z, @5 j$ m. G# }5 c
    对于很多刚入门的小伙伴来说,了解爬虫的工作原理是非常重要的。只有当你了解了它的原理,你才能结合实际情况写出对应的爬虫。下面我将以通俗的语言方式来介绍爬虫
    9 M4 G" }# ?8 }5 z( `把互联网比作一张巨大的网,那爬虫就是这张网上面的一只小蜘蛛,在互联网上面有很多的数据,各种各样的数据,我们可以把这些数据比作是被网粘住的小昆虫等。爬虫的作用就是去找到自己喜欢的口味,然后把它带回家,可以储存起来,也可以马上享受美味0 m# Z& z7 p) P: X* j* E4 U
    所以说爬虫分为三部曲:; r! B9 u+ J8 s
    1、明确你自己喜欢什么口味(制定需求,明确你需要的数据类型)
    8 Z" d; f/ E1 @* z5 |  m2、去找到你喜欢的食物的位置(得到目标地址)8 W1 q& H" T# o
    3、把食物搬回家去(解析网址,获取数据,存储数据), S' ~5 T# b) T* ^
    它的整个流程就是:(简单的通过request请求获取数据并解析获取数据。以下都是固定化格式,可以照搬)
    8 ~8 M! g# d# Y. K" ^' Aa、导入需要的库 requests6 g7 ^5 B1 }# {3 g
    1 j1 r" h8 n6 v: _, N; l
    import requests% @& y% O3 D6 j9 N* f; A* |
    1
    5 r% D; v8 k1 p0 P6 w! `8 D# ^5 pb、明确你要获取数据的网址(这里以百度网站为例)- i. O, {+ w- Q; C
      b: Y1 W. R6 ]
    url = 'http://www.baidu.com': j9 m7 U& O1 v3 E' e( T% {
    1* a/ z  ]$ i2 _1 x3 ?+ U& S% o) q
    c、创建请求
    & i5 E" W0 N# J4 i, F2 \; q6 [6 L$ x6 R# I& z
    response =  requests.get(url)1 `- J/ ?$ [3 |5 i
    1/ M/ |( j- ^5 j0 W5 c! S
    d、测试请求是否成功(在实际应用中用的比较少,正常情况都是可以请求成功的,网站对于访问外部信息的爬虫是不会做出限制的)
    1 ?( C' ?1 f6 q* b- L# L- i
    - m8 R$ K8 b' y* I& m2 k3 Qprint("状态码:",response.status_code)$ @, P( P- p/ N2 n* n" }* W
    1  o1 q, z8 f& \5 M- l9 u+ A4 _
    当状态码为“200”时表示请求成功;如果不是“200”,很大可能就是你的目标url写错了,核对一下url6 N& Q0 a1 e4 Z  m' c% o
    e、得到网页源码
    6 a( C5 i0 V+ ?: T0 P; B! X
    3 u3 H0 c2 @6 d0 X* K9 ?print("内容:",response.text)
    # J1 }& |1 c( W5 y) H# r. h1: m5 ~( d. }* r$ C7 M1 Q
    response.content是response.text的二进制形式) }; ]5 s; ?( z" q: Y$ W# F

    0 m1 z( I1 f/ P至此,一个简单的爬虫请求就算是完成了。
    . C: p: {/ K, f; J当我们请求目标url并获取到response后,就需要进行下一步:解析网址并获取数据
    1 l/ V6 p; S. `' E6 [f、解析网址
    / I) S. O5 {8 [: W3 H! m刚开始学习阶段,我们最常用的两种方法,一种是BeautifulSoup,一种是etree。其中BeautifulSoup是最常用的。以下将对两种方法分别进行介绍 (以下方法均为测试用例,实际当中应结合自己的实际情况选择应用)+ ~; C1 _" h' H  H2 M# U- l) f
    BeautifulSoup:& Y8 l4 x8 O8 w1 E1 q. ~# H
    首先导入需要的库文件:. C& R9 R; O6 Q

    9 H% W0 c' {  O( f2 qfrom bs4 import BeautifulSoup
    , n/ H* I0 W# K4 D& B1
    % b7 O7 B9 c1 ?, x% y0 K然后对上面请求得到的response进行解析:
    - z5 Y! R6 q+ a  z! {
    5 }8 N  h0 G- W( h7 Khtml = respone.content.decode('utf-8')
    4 ]* m9 I9 p( Bsoup = BeautifulSoup(html, 'lxml')
    9 U  v$ u' C2 s! G& A1
    ; p( N( ^9 D( q7 L- O  i23 M' }8 K8 p' a
    以下是BeautifulSoup中比较常见的方法,有兴趣的朋友可以去一一测试:# I: o' t1 G+ ]' _# V( r5 I- y
    # 获取head标签
    & {$ |$ V9 H6 {) x+ d0 N% Uprint('head标签内容', soup.head)
    ( w, K5 D0 |7 u# 获取title标签
    2 k* E9 j, O  y0 \print('head标签内容', soup.title)1 I6 ^* E. ~9 B8 r
    # 获取body里面的img内容
    + x( A; t, B$ g# 通过点号的方式只能获取 下属第一个标签(即获取soup下面第一个body里的第一个a标签的第一个img标签)& r' S* a* B6 v- d4 R
    print(soup.body.a.img)   
    6 z* e* p7 F3 w3 F- B# 获取所有的img标签  使用find_all()搜索整个soup对象
    , y* Q$ I) _3 N6 n* y# x+ yprint("获取所有的img标签", soup.find_all('img'))* m7 U9 p% N2 p! F8 z5 I9 o
    # 获取标签中的属性src地址
    . I( f) |3 a1 a- C4 Nprint("获取标签中的属性src地址:", soup.img['src'])      # 注意:英文点号都只能获取第一个值
    * H( n) E7 ~4 R4 z4 [! u+ d7 G- N6 V: a; B# X) |

    9 W0 J( _& {5 v/ k, k8 q) @# 获取soup的name
    0 t1 {3 X- f; m# V7 a% R9 cprint("获取soup的name:",soup.name)
    " q8 u* r1 |5 d/ Q4 i# 获取a标签名+ v  W- K  i3 Z  u. q
    print("a标签名字:",soup.a.name)
    2 C. Q* Q6 U4 m/ ftag = soup.a
    * t& @7 V) f/ u+ Hprint(tag); i8 g, G* v; m7 ~' h) q- J8 x
    # 修改操作  a标签改为b标签
    7 E5 b. X. G; y, ytag.name = 'b'   # 赋值后<a> </a>变为<b> </b>
    1 ?  p) e) ]8 M4 K- j# 输出修改后的内容# [! h0 A8 ?3 l. D6 B2 N5 G
    print("输出修改后的内容:",tag)
    5 |1 D9 N8 Y6 O9 g) e& i5 f) C# 获取全部的属性 attrs
    5 r' [+ ?2 s3 G- Qprint("tag对象的全部属性:",tag.attrs)   # 只能得到当前标签的属性(不包含下属标签)3 H! }0 \5 ]6 g+ Y" I. O, r

    3 D# d# q( w; k9 h* N/ h# 获取属性的class的值   根据键取值
    . L. f3 ~, U3 ?9 l! B. K6 cprint("获取属性的class的值:",tag["class"]): _% B5 L4 n% g$ @$ `/ x
    ! G8 b# J. N' y- t" ?' o
    & B5 }- Q8 J) ^  d; ^

    ) q- I. r4 y* N, I; x) s$ A6 d4 N' @$ U' C, B
    """针对获取的标签属性可以进行增删改查"""7 Q/ X- Q! ^' h3 @
    # 修改, x$ ^4 a  H0 w5 J0 p  l
    tag["class"] = "Logo") V: h7 i# [9 `, [; t' s) @: {
    print("tag对象的全部属性:",tag.attrs)# p: Y, s, h) C7 W. r2 l
    # 输出属性5 s( c* I3 v3 F: M+ t/ @- ]% }
    print("获取属性的class的值:",tag["class"])
    0 o" c$ g( S) G# 新增  属性id  赋值logo* f/ {0 l$ O0 a2 [8 S
    tag['id'] = 'logo'* D9 i8 V/ }% n
    print("tag对象的全部属性:",tag.attrs)' t& b9 k* z) X8 n6 f( A: K
    # 删除属性) h+ ]# t/ |( g" [5 n
    del tag['class']
    ; x% c4 k' c% D$ ]  m. y- t; jprint("tag对象的全部属性:",tag.attrs)9 |2 f% C& I6 O/ }" L1 u. X8 i
    7 N+ n4 ?# u8 v5 T- N" U
    2 ^/ N2 S$ Z+ U4 |* I0 O
    0 I* d4 `* z0 X, ]( B2 `" y: E% Q- w
    """针对内容操作  (只针对标签,对属性无效)"""
    2 \+ @* u* N; M) O+ x2 N# 获取title标签内容+ w; q4 B+ V7 {7 {: l
    tag = soup.title3 Q- R5 R* C6 v% ]: ]+ s. m
    # 获取title字符串5 N' T0 O' D, n
    print("tag对象所包含的字符串:", tag.string)
      h& D- u) ]# w5 b! y6 w+ bprint("类型:", type(tag.string))) a  T+ T! K; `# P- X
    # 替换内容; X! b7 |# w# y  S5 g
    tag.string.replace_with("你好")
    1 v8 z' ?4 y3 y0 uprint(tag.string)$ x/ O# q# w6 Z/ p" h1 R3 S$ U
    # <!-- 学科建设 -->; D$ [) j- g) {: t' x! ^' U1 k" ^
    # 获取注释文本内容; ], x, c( Z& p; W5 Z/ q1 H! E
    markup = '<b><!-- 学科建设 --></c>'
    . V- L: ~+ u1 {: K' l8 @7 ysoup_comment = BeautifulSoup(markup, 'lxml')! u$ b# m0 n& W- p, ~. ?- K1 e7 p
    comment = soup_comment.b.string                    # 以markup第一个标签作为关键进行搜索. n- H7 |4 A- \6 p- B8 x" X
    print("获取注释文本内容:", comment)
    8 l$ L- u0 S% y' h% c, T. x# get_text()9 R% Q4 T; B6 C( M
    print("title的全部节点:",soup.find_all("title"))+ p4 }5 {7 U/ L" r2 Y
    print("title的内容:",soup.title.get_text()); @8 ~& t; K" K& m) g8 B1 ?. ^
    """查找ul元素标签"""
    * E6 ~8 f2 f1 R! v# class是关键名,匹配时后面必须加下划线_  a: i$ f2 L9 v# u( A
    # tag = soup.find_all("ul", class_='menu')  # 按照css类名完全匹配1 {& f+ x, M+ {, H
    # print(tag)
    " i1 T7 \# }" ]) y+ ~5 }9 Ttag = soup.find_all("ul", id='menu')  # 按照css类名完全匹配
    4 x4 t* x9 o7 t: v* h1 _print(tag)
    ' j0 j* u6 B2 p# f: ~5 f# 查找名称为a元素的标签内容/ w1 g4 W8 D4 ?4 w: P; v
    taga = soup.find_all('a')' `5 |7 Z1 ]" \* |. @% M
    for tag in taga:8 j5 h/ B7 F3 v1 _5 m* g
        print("查找名称为a元素的标签内容:", tag.string)1 P" n$ M- R0 s, J( a0 f2 E
    # get 获取属性信息  获取整个页面的img标签图片和src属性值
    $ z" V- v( q$ d7 A! N) E' Gtagings = soup.find_all('img')- V4 ~* ]. t0 ]8 s, @$ W2 U
    print(tagings): f1 o2 [) G/ Y. h$ [4 d% ?7 l5 j
    # 循环输出图片地址: A4 J" \1 {+ E9 ?+ ~( e5 ~
    for imgsrc in tagings:8 n  [. ~" x- b9 u4 r
        print(url+imgsrc.get('src'))
    " O  Y) W4 O3 _- o  y; ?2 }: X+ Q$ h/ w
    """"属性只能做为参数,所有的操作只能针对标签"""
    6 E( H/ w' J6 p9 `/ b* P0 u7 V; [6 s9 P. Z
    etree方法:4 _; b" K# |4 x) B; r; t
    导入库文件:; u. d5 c; N( l% v; p+ Q
    # {' f: k6 i/ b4 z7 }
    from lxml import etree
    6 F' x& J! ]+ _' p& u1" R& H, j; `9 y2 w
    解析得到的response对象;
    $ _5 G. r) m; L( {
      J3 A4 u$ Q% y: i! [8 |# 设置response的字符集5 Y* u$ s+ _# n! F+ R
    html = req.content.decode('utf-8')2 o% {! i5 ?- c: p+ K  \* c) S
    # 解析对象% v( W5 P0 x; b" ]; ~9 ^! D. I
    html = etree.HTML(html,parser=etree.HTMLParser(encoding='utf-8'))1 U" ]! C/ c: I9 m/ t  Z+ O

    * z$ ?* `' n+ r9 m" z常用的方法:
    0 q  Q$ s/ m' Z, k
    - V# U3 Y. `2 o  @1 J5 K( D# A% F/ p. q  ]; P
    # 定位head节点(元素)" U. h; G5 b# {/ U! x8 x5 O; i2 a
    result1 = html.xpath('head')
    * Z1 m0 V% T8 H, ?9 D3 Uprint(result1)$ s4 r* }( Z9 i. i3 Y3 ]( b2 x
    # 定位title节点
    ! n9 ~& S, h2 x! B, ?' k5 fresult2 = html.xpath('/html/head/title')2 d& a: m' G/ a  u# _/ I
    print(result2)4 N; R1 d8 X5 |: i
    # 搜索节点  title节点
    : K: r( n( X' y( k* o  J1 j3 Yresult3 = html.xpath('//title')
    ( D- E, Z% @5 n$ r9 m, iprint(result3)% X. d5 T: z7 u2 X
    # 搜索title内容  text()得到文本信息* I, q. {3 Q; B  W' x; v
    result4 = html.xpath("//title/text()")
      g5 L1 N! F+ Y5 U7 J2 x, rprint(result4)# b. y; z8 W" ~) W7 v
    # 搜索div节点( d5 ^+ @* r4 k+ V
    result5 = html.xpath('//div')7 l/ _8 ]% S9 _
    print(result5)
    " u+ w0 A$ J. A, Z" Y) ~9 J, \# 搜索div节点 并用class属性定位
    5 w' ?" n; F& r6 wresult6 = html.xpath('//div[@class="news"]')
    % l( N8 R; d% b. `8 u" I  ?* wprint(result6)3 k- M1 J3 Y- w, D
    # 搜索div节点 id属性定位
    2 Z6 k( u! s4 p5 V% n+ Aresult7 = html.xpath('//div[@id="news"]')- ^0 A: D. i; J" J! D  S
    print(result7)  y' z; `3 b1 P9 V( s. i7 f- s2 U9 q
    # 获取列表span信息
    6 {; c, I) P6 N' o' L- z8 q1 l  H! Stext = html.xpath('//div[@class="news"]/a/span/text()')) M% ~2 |! F; |- m  A0 ]* ?
    print(text)/ i$ w" N5 U6 ~" A% ^% d" n  F

    ) H7 m1 L7 s1 m6 [' \( ]0 _

    g、通过上一步我们得到自己需要的数据后,下一步就是将我们得到的数据进行保存
    : H# P$ o$ n2 n5 k! _保存的方式有很多种:/ X6 a8 e1 T) {- @- r  M5 |2 n) B
    1、保存至文件
    ! A, U( g6 [0 U2 E4 \csv、json、text! Y$ _7 B+ p. d- j" M
    2、保存至数据库+ o& C3 r3 J7 q
    MySql、MongoDB、Redis 等 (目前主流的为以上列举的三种数据库)

    关于数据存储后面再做详细介绍
    2 k, r, @, J0 q" P' K8 ]0 P( R, L* _6 A  t( n# t

    5 V  X1 Y0 A% |————————————————
    8 \3 j5 Y8 R+ C- F版权声明:本文为CSDN博主「royallucky」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    : s! d7 ]2 F6 ~2 h0 t) W  k原文链接:https://blog.csdn.net/royallucky/article/details/105930473; |6 }9 z3 [; J# N
    ; x8 R" S3 {+ j8 y: k: ^

    : {& Q$ A' e4 `% h; i5 J; ?- n+ k) m
    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, 2025-9-15 19:23 , Processed in 0.538477 second(s), 56 queries .

    回顶部