QQ登录

只需要一步,快速开始

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

    + f0 e/ M& M7 {/ Z0 @

    0 ^* {- B+ ]& c  f

    6 y# v% V3 {; j. p2 i
    手把手带你5分钟搞定爬虫(聚焦爬虫)

    2 |6 L& E! n. Q, S" l
    $ \! ~8 W0 O, q/ S爬虫的原理
      ]# m( H5 [. q0 }( U6 e+ c" v5 k; ~* N) s; {4 }$ W/ f
    对于很多刚入门的小伙伴来说,了解爬虫的工作原理是非常重要的。只有当你了解了它的原理,你才能结合实际情况写出对应的爬虫。下面我将以通俗的语言方式来介绍爬虫2 }+ X: O$ H& `4 I( e2 D
    把互联网比作一张巨大的网,那爬虫就是这张网上面的一只小蜘蛛,在互联网上面有很多的数据,各种各样的数据,我们可以把这些数据比作是被网粘住的小昆虫等。爬虫的作用就是去找到自己喜欢的口味,然后把它带回家,可以储存起来,也可以马上享受美味0 Y" p$ ^  a9 e, I
    所以说爬虫分为三部曲:8 {; W/ P5 b% E
    1、明确你自己喜欢什么口味(制定需求,明确你需要的数据类型)0 n& |8 e; s$ w
    2、去找到你喜欢的食物的位置(得到目标地址). y" ^3 P. M/ U/ Y  [# h+ ]2 K
    3、把食物搬回家去(解析网址,获取数据,存储数据); g/ V2 ]  ]# K$ a2 @
    它的整个流程就是:(简单的通过request请求获取数据并解析获取数据。以下都是固定化格式,可以照搬). K- X+ i. n' Q0 ?0 j  c
    a、导入需要的库 requests
    , |1 b/ a. n8 @; E# i
    : i- `0 O5 T& L- Q! Dimport requests
    9 N8 ?/ G" C  e9 Y" b" Q7 A) i1: g. w! A$ X# I7 r2 l: J% A. E
    b、明确你要获取数据的网址(这里以百度网站为例)' [9 l7 f9 s4 p# x2 O3 ?

    " e# R3 r" J' x- Q/ `url = 'http://www.baidu.com'' L' K1 d- X; x/ y; b" G
    13 M6 s# m* H4 t
    c、创建请求
    % ~6 q9 g  a! x$ X% ?6 Z; R; S( p# O
    & Y' u$ U4 \. B5 Y9 qresponse =  requests.get(url)
    ) [* R7 ]: V" W1, J! [0 j% W: ~+ P
    d、测试请求是否成功(在实际应用中用的比较少,正常情况都是可以请求成功的,网站对于访问外部信息的爬虫是不会做出限制的)
    ! a" Z( U8 j9 n& Y9 x) s5 Z2 }0 b9 q
    print("状态码:",response.status_code)
    ) k$ ^/ _; b8 y5 @: |" i1 f1/ i% `0 F% N% I: _- S8 E
    当状态码为“200”时表示请求成功;如果不是“200”,很大可能就是你的目标url写错了,核对一下url
    2 w5 }; i7 L# `e、得到网页源码
    6 F; ~. F+ _5 f! ]3 U4 ?" i. l: }" N6 V, u" }% T4 X. M  V
    print("内容:",response.text)7 g  w5 i$ w/ G1 }+ _6 p! ]
    1
    : \, ?1 y# X) e  k  W" ]response.content是response.text的二进制形式- u, p3 q" T7 ~8 ~$ P

    ' z1 N0 |9 U4 Y6 L+ g3 c6 X至此,一个简单的爬虫请求就算是完成了。
    5 K9 o( l% _- z) d当我们请求目标url并获取到response后,就需要进行下一步:解析网址并获取数据  `2 _, ~7 h: k( a
    f、解析网址7 }! c# l+ w( G0 L+ o; N0 W
    刚开始学习阶段,我们最常用的两种方法,一种是BeautifulSoup,一种是etree。其中BeautifulSoup是最常用的。以下将对两种方法分别进行介绍 (以下方法均为测试用例,实际当中应结合自己的实际情况选择应用)
    $ |, _  C  m: Q$ L; Z' Z7 vBeautifulSoup:! ]- {1 H/ o4 x* Z8 K* @6 z
    首先导入需要的库文件:
    6 ^7 ]( `0 V( R" K/ [3 Y2 q8 |* M; D; e  _
    from bs4 import BeautifulSoup
    2 P( K9 y: v& _& J7 H9 M- U! r" e1
    ' ^, K6 S, @0 V然后对上面请求得到的response进行解析:
    - W+ [6 c- n! D  k- e+ T2 z& {* s
    html = respone.content.decode('utf-8')
    0 `4 ?' J7 ]$ \& j+ I" h3 ]* msoup = BeautifulSoup(html, 'lxml')8 t+ o# ]9 h( }/ h; O
    1
    / f8 ^+ Y% G! q2
    ' C* Y% @3 H4 }: Q$ ~( T: l6 F" B1 b以下是BeautifulSoup中比较常见的方法,有兴趣的朋友可以去一一测试:
    : u+ M& [: ?8 M+ j& C6 w# 获取head标签
    $ p( _8 J. ~: f5 ]/ o0 {print('head标签内容', soup.head)
      n! d% Y! B) H9 Q( F+ ?) w# 获取title标签
    5 s8 d! f2 d- Jprint('head标签内容', soup.title)
    7 ^) R4 ~/ S) B- B- ?# 获取body里面的img内容+ h: m' W# k. Y3 F
    # 通过点号的方式只能获取 下属第一个标签(即获取soup下面第一个body里的第一个a标签的第一个img标签)
    # S2 c; W# n* Y1 nprint(soup.body.a.img)   
    ) r( y5 S; A- b2 E' X# 获取所有的img标签  使用find_all()搜索整个soup对象
    : I7 G2 t, m7 h5 Z0 \8 `print("获取所有的img标签", soup.find_all('img'))- v) d2 e0 _& S7 a$ A
    # 获取标签中的属性src地址6 F0 M$ Y8 i2 n# Z9 d
    print("获取标签中的属性src地址:", soup.img['src'])      # 注意:英文点号都只能获取第一个值! p8 i! k/ T- t3 d

    / ?; C' C6 n+ P9 d5 n. A8 a  s7 \: b' m6 I% @, z8 J1 R  K" N! ~
    # 获取soup的name7 b" B$ s5 c2 Q! J9 b2 p9 \
    print("获取soup的name:",soup.name)3 l2 |2 e: G' c5 X
    # 获取a标签名
    + g! R. ?/ F5 v, J+ [, aprint("a标签名字:",soup.a.name)
    , u& F1 ^4 {: K- f' y6 y$ Rtag = soup.a
    8 n( Y" z* R+ I; }- Dprint(tag): Z# s8 J3 ]8 E* H) J7 Z
    # 修改操作  a标签改为b标签0 ]* F! h( ~; s5 V4 p: F
    tag.name = 'b'   # 赋值后<a> </a>变为<b> </b>! }. V- Z8 h7 B* l! J
    # 输出修改后的内容
    % C, Y/ x  @# G; xprint("输出修改后的内容:",tag)
    $ l- x0 _4 W6 j+ v7 J# 获取全部的属性 attrs4 `: e' b1 m! U! Z# r7 ^
    print("tag对象的全部属性:",tag.attrs)   # 只能得到当前标签的属性(不包含下属标签): O7 y) C5 Y: c- f) l4 @
    , D+ c6 V2 j# `
    # 获取属性的class的值   根据键取值. Y. o: F( y& e, M  U" j( i- m/ j; T+ {
    print("获取属性的class的值:",tag["class"])8 U; y+ d& C$ `6 w3 j- B

    + [2 z8 S  q' N% s; y
    # o. g# @. w3 z; w" X. o5 g
    # v. n2 ?$ `5 ?  A' I& e: e, O, x$ o8 w7 C* D
    """针对获取的标签属性可以进行增删改查"""4 j4 A8 _4 J$ Z
    # 修改
    , d8 K  B4 k( v) h0 L0 itag["class"] = "Logo"
    , S8 T0 s1 P$ a, J# _8 @print("tag对象的全部属性:",tag.attrs)
    9 C! }, k! E: [% X' _# 输出属性' @7 `# j7 w* ?( j% s+ P+ T
    print("获取属性的class的值:",tag["class"])& ^) R" u5 d  j) V+ s4 r
    # 新增  属性id  赋值logo8 l" \. v% S8 c! H5 F, q
    tag['id'] = 'logo'
    / H" c4 s- F2 S) o; gprint("tag对象的全部属性:",tag.attrs)
    ' ^  l4 X/ w7 v9 u' f# 删除属性
    ) b/ a2 B7 Y) [. fdel tag['class']
    " k4 e0 W/ h$ R  Uprint("tag对象的全部属性:",tag.attrs)7 |+ W9 ]- v0 P4 N/ o, r6 ?
    , {& S8 n( D/ z0 L# X
    8 w" a' E. r. o7 x
    8 Z: u9 i9 b& m
    """针对内容操作  (只针对标签,对属性无效)"""
    3 u, c! O) h9 j2 a' J# 获取title标签内容
    8 I; n! i: ]8 B+ P  ttag = soup.title- F/ M% z, g5 c" Y
    # 获取title字符串: Y; s* S& \% n, B6 R
    print("tag对象所包含的字符串:", tag.string)
    3 m( R% @4 |6 P" j( V. R5 kprint("类型:", type(tag.string))
    5 r: A  ?: {( v/ B% [. f# 替换内容
    : R" D( Z3 l' M# L! |1 W. r  o' jtag.string.replace_with("你好")
    / a$ Z" s6 t4 cprint(tag.string)8 E9 P$ D. g. ~& }2 ?: Q4 R: Q
    # <!-- 学科建设 -->4 N1 Y$ \- {/ C4 u, l- g
    # 获取注释文本内容
    , R1 S  b# [' [markup = '<b><!-- 学科建设 --></c>'& {' e$ ^1 \7 A' T
    soup_comment = BeautifulSoup(markup, 'lxml')
    0 ?: U* D0 q7 r5 c9 ncomment = soup_comment.b.string                    # 以markup第一个标签作为关键进行搜索6 |3 j: m2 Y9 r$ M0 Q
    print("获取注释文本内容:", comment)
    9 t7 K2 U5 u2 R4 A/ X) q6 A# get_text()1 c* {+ h/ ]+ v, u& ]6 v
    print("title的全部节点:",soup.find_all("title"))  m3 W( m9 i& j% s! `
    print("title的内容:",soup.title.get_text())3 {2 q% k. [" H4 r0 w
    """查找ul元素标签"""& }# c2 K5 Q5 b
    # class是关键名,匹配时后面必须加下划线_
    - P% W  T+ M- p& G7 e# tag = soup.find_all("ul", class_='menu')  # 按照css类名完全匹配
    - m! d$ ?5 W) J/ R# print(tag)
    & |0 a8 t0 O& ktag = soup.find_all("ul", id='menu')  # 按照css类名完全匹配
    # H3 v8 F: O3 j# w- l5 Hprint(tag)
    1 P- n8 D( X" ~2 g# w1 j6 m# 查找名称为a元素的标签内容/ e4 c4 g1 b: [& w3 W4 e5 A( W
    taga = soup.find_all('a')
    , U, V; |9 B  o4 F0 l: ufor tag in taga:" y/ A# \- [( o' z
        print("查找名称为a元素的标签内容:", tag.string)) u# i) v5 P, i" d0 ?
    # get 获取属性信息  获取整个页面的img标签图片和src属性值+ Y  |& r7 h4 _) [0 B5 @$ e1 R
    tagings = soup.find_all('img')- _+ K+ a) ~  w, ^0 G
    print(tagings)
    2 i- b; u+ Q9 G7 V% W  n# 循环输出图片地址* B% |4 X& T! L3 w$ }1 H" i7 Q
    for imgsrc in tagings:. Y  p5 g$ h2 P' v! @
        print(url+imgsrc.get('src'))( k. h. h9 A  s
    6 W4 p: J0 |& E8 r) d4 Z0 p
    """"属性只能做为参数,所有的操作只能针对标签"""
    7 h( V0 M( Z  p  `1 [( ~: |8 r/ P
    5 ~  U% U% r- ?  p* Setree方法:
    + k1 `$ Z$ \3 D# \# T- k$ J导入库文件:
    # Q) v8 O# F( x0 ~
    ) M: G8 f: u4 Cfrom lxml import etree
    ! \2 v- Z9 f1 q. t/ z1
      k2 @( k: j3 M- l! s( G4 I解析得到的response对象;
    5 m1 \% ^# g# @9 G- S: X; _; e, D6 z- J  B! X
    # 设置response的字符集8 T2 j# M- O7 L, Z, Y
    html = req.content.decode('utf-8')6 `" C* O% u* K+ \. r1 b
    # 解析对象
    , z! |% m- p. U; thtml = etree.HTML(html,parser=etree.HTMLParser(encoding='utf-8'))7 d4 \& r* h. l+ Z# [. V3 ^

    ! P  ]& a  d1 I常用的方法:
    3 A! o1 g& ]8 b$ A$ X9 K- P% i
    ; ]) w6 V5 ]/ |* Z% z# j
    ) u/ k1 k( p9 H" I! g: ?# 定位head节点(元素)* N! p0 L0 y5 u/ G; E
    result1 = html.xpath('head')
    & Q3 `! k4 S  v* Qprint(result1)# w5 s5 _6 b* ?" s# T/ N. s
    # 定位title节点
    . {4 P; I4 g+ u1 K3 {+ c& Zresult2 = html.xpath('/html/head/title')
    - ^5 F0 u' j" u4 m- ^0 n* B/ Y8 qprint(result2)
    7 H) s1 k8 u; d# 搜索节点  title节点0 E; m' A$ o# _7 k" j
    result3 = html.xpath('//title')" s. O. D. j) N4 I) l- b3 j- Z  A, [
    print(result3)
    6 ~0 ?6 o4 K& K7 ^# 搜索title内容  text()得到文本信息
    " E& v% H) k4 a! Q: Mresult4 = html.xpath("//title/text()")0 y+ C3 @. N% I+ R2 C1 G
    print(result4)
    $ V+ b4 G0 ]7 {3 q# 搜索div节点
    4 N% g+ X- a/ K- ~$ u1 k2 j( Aresult5 = html.xpath('//div')
    9 y% A7 m7 p6 d3 Iprint(result5)
    * D% e5 u1 p: W7 L2 b& {+ P# 搜索div节点 并用class属性定位
    : L5 c1 O' [* f& L) uresult6 = html.xpath('//div[@class="news"]')6 c7 e) Z; ?! q- ?' A1 l5 q
    print(result6)* [+ z3 R* ]. K/ M9 R: Z+ F. ]" x
    # 搜索div节点 id属性定位0 o, d: ?6 G1 r; J& F7 J' O
    result7 = html.xpath('//div[@id="news"]')0 a6 D  A/ B+ y/ O
    print(result7)# g! i% \; ^- w3 ]0 c: x
    # 获取列表span信息+ m. B; G2 c! x+ x" T. }
    text = html.xpath('//div[@class="news"]/a/span/text()')5 q5 {, l5 ~$ k# o5 R8 e
    print(text)
    ( J. @; X  S7 E* r; ?1 [4 I+ @' G1 K$ o1 i% s/ f

    g、通过上一步我们得到自己需要的数据后,下一步就是将我们得到的数据进行保存
    9 m! e. J1 J, ^0 R0 Z6 Y, ~2 ~保存的方式有很多种:
    $ C6 h- d4 H/ J# T6 d1、保存至文件
    $ t" r* y: e9 ]" \/ k) ucsv、json、text
    8 X# W7 i9 D& M! S% I" n7 n0 e2、保存至数据库) Y7 ]" A. _, [$ j
    MySql、MongoDB、Redis 等 (目前主流的为以上列举的三种数据库)

    关于数据存储后面再做详细介绍
    # g- n, @( J+ i7 ^! O
    % [; Y4 Y* |( `3 ^9 o( E
    * n' f) [& D8 w————————————————7 P1 ?. R5 c+ _" p7 v
    版权声明:本文为CSDN博主「royallucky」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。. a/ @. L7 ^2 J7 O( L  e
    原文链接:https://blog.csdn.net/royallucky/article/details/105930473
    7 d" S3 ]6 @$ a" e  O7 R5 W8 X$ V3 }. _

    " Q+ t+ Q) x0 a9 {0 c% A0 }9 A! {6 \. @
    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-4-11 16:08 , Processed in 0.448315 second(s), 56 queries .

    回顶部