QQ登录

只需要一步,快速开始

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

    5 O/ e( ]$ p% r8 A+ e6 M

    & v6 |  j1 t* s& c1 ~& {

    8 q9 ~9 W0 `% ]/ N2 v0 D/ Q
    手把手带你5分钟搞定爬虫(聚焦爬虫)

    & p" G7 u* S. E2 S& k
    1 W; v9 m. ?% F+ V; l爬虫的原理
    , S$ R$ q, z  l$ }1 J6 Z# \0 r, ]$ F& W: ]1 {+ y
    对于很多刚入门的小伙伴来说,了解爬虫的工作原理是非常重要的。只有当你了解了它的原理,你才能结合实际情况写出对应的爬虫。下面我将以通俗的语言方式来介绍爬虫
    8 Z0 u) ~4 [4 `; {9 @4 m+ J% c把互联网比作一张巨大的网,那爬虫就是这张网上面的一只小蜘蛛,在互联网上面有很多的数据,各种各样的数据,我们可以把这些数据比作是被网粘住的小昆虫等。爬虫的作用就是去找到自己喜欢的口味,然后把它带回家,可以储存起来,也可以马上享受美味
    5 V0 A2 O4 S/ D) X& g所以说爬虫分为三部曲:/ _9 Y$ u/ A0 e8 N& t
    1、明确你自己喜欢什么口味(制定需求,明确你需要的数据类型)9 G" q5 e5 N. v" F8 G0 G9 p) [1 U
    2、去找到你喜欢的食物的位置(得到目标地址)# \5 g9 p4 y4 C. B0 I' B) @' J
    3、把食物搬回家去(解析网址,获取数据,存储数据)
    . A& g" w* u! h' D, X5 @8 o7 g它的整个流程就是:(简单的通过request请求获取数据并解析获取数据。以下都是固定化格式,可以照搬)
    5 n' k' E$ M% p3 {& O) Pa、导入需要的库 requests
    ' z  h( c3 s. D6 K! O  b+ d. t
    ( ]( o  |( O2 Fimport requests0 P% g0 O1 z& z- [- g2 ?
    1
    4 b5 u9 d+ n$ b2 j/ W- I- eb、明确你要获取数据的网址(这里以百度网站为例)
    5 W; ^: Z( T  d7 a" L9 }: |
    0 V2 B: M5 }7 l7 }2 ~url = 'http://www.baidu.com', C' Y8 D: {4 {6 l- z  P0 ]
    1
    " S" \! q3 U: s- J& V' `4 F4 n. Zc、创建请求  a7 f0 B4 Q5 {6 A

    2 u: N0 o, v* L; h. Presponse =  requests.get(url)  g8 W) M2 M7 j7 ^
    1+ {" v" I1 n! E0 O; i
    d、测试请求是否成功(在实际应用中用的比较少,正常情况都是可以请求成功的,网站对于访问外部信息的爬虫是不会做出限制的): h- u1 l+ F# K/ {% `7 X; x$ t+ B
    0 o  D4 E. m; J
    print("状态码:",response.status_code). E& N( ]) z; `* n/ G/ z9 P
    1) j! m% b( d! o6 s5 D6 e7 }, Q$ x
    当状态码为“200”时表示请求成功;如果不是“200”,很大可能就是你的目标url写错了,核对一下url; E; w* G# @4 i" ~/ @
    e、得到网页源码5 u, ?" q4 V5 c8 L1 e( A, J. P5 a. B
    6 w5 z7 R! m) Y& c( h* w
    print("内容:",response.text); a6 f6 y! c, I5 t0 k: p  p, N
    1
    8 a" _5 x7 X0 _! ]* a4 \' {response.content是response.text的二进制形式
    & T! I  y5 G+ p2 T, P) G
    / N* ^8 v! v  j至此,一个简单的爬虫请求就算是完成了。, j' V7 u. b0 M7 F: J  k8 _
    当我们请求目标url并获取到response后,就需要进行下一步:解析网址并获取数据1 y2 T% ^- c( j) }
    f、解析网址
    " K) g4 T7 S0 ]刚开始学习阶段,我们最常用的两种方法,一种是BeautifulSoup,一种是etree。其中BeautifulSoup是最常用的。以下将对两种方法分别进行介绍 (以下方法均为测试用例,实际当中应结合自己的实际情况选择应用)
    . c! ?5 E; p# h' t# H, A6 }BeautifulSoup:
    4 W, h5 X4 x' `, L. N首先导入需要的库文件:3 {) \: Z6 G+ ~, O& o

    3 @: W* K  Y0 P  C  x* c! g+ {from bs4 import BeautifulSoup, z; R2 }. C9 n+ l) t- E
    1) |2 k  G  Z8 d
    然后对上面请求得到的response进行解析:
    8 w1 t4 |+ R% W7 j$ [5 @- C" a# j$ e8 v2 m8 u8 Z& M1 {& ?" M
    html = respone.content.decode('utf-8')
      R( k/ N, o4 T* q3 T) wsoup = BeautifulSoup(html, 'lxml')5 D( |+ Z5 Z7 _) I; ~/ k+ p
    1
    $ e8 C+ y; _( r7 v8 n$ n' Y+ _) m2
      K3 H) M2 k$ B6 E: t- R以下是BeautifulSoup中比较常见的方法,有兴趣的朋友可以去一一测试:
    % i" S, ^1 W7 w% J3 U# 获取head标签
    # X3 m, C5 @3 N, g  Lprint('head标签内容', soup.head)
    1 E# F' L5 e. I9 F$ s# 获取title标签: T( R( v) t# r5 @$ ?$ P
    print('head标签内容', soup.title)
    : S' P% f5 {; T, C1 t# 获取body里面的img内容
    ( w" |4 j0 q+ f# 通过点号的方式只能获取 下属第一个标签(即获取soup下面第一个body里的第一个a标签的第一个img标签)3 `. d) Q6 ~: O* P. |3 t" n9 U
    print(soup.body.a.img)   # G% t: I2 w7 x/ k) z" b
    # 获取所有的img标签  使用find_all()搜索整个soup对象$ ?: J$ v! a0 t9 y
    print("获取所有的img标签", soup.find_all('img'))
    ' w, F6 ^$ _& e+ c  |6 L# 获取标签中的属性src地址  s7 a4 t' E" U
    print("获取标签中的属性src地址:", soup.img['src'])      # 注意:英文点号都只能获取第一个值4 @+ r( M$ [, l' }: _
    & I2 t5 r5 |, b" d

    8 L2 p* F0 E2 P! S# 获取soup的name
    6 g# V) u" N. a+ o( y0 i( {print("获取soup的name:",soup.name)
    $ O, _, X8 Q2 Z6 p* E# 获取a标签名
    $ d  Z' }+ T2 _; t" [% f# @print("a标签名字:",soup.a.name), Z3 n* x: I! H) `
    tag = soup.a
    $ v; b$ f* k8 A: }print(tag)# i4 j2 X( p/ g3 H1 N  w" t9 s
    # 修改操作  a标签改为b标签
    2 B9 i4 n, I$ D8 O7 C- Ctag.name = 'b'   # 赋值后<a> </a>变为<b> </b>
    / G8 @1 z' [# c/ Y/ j! c% h8 e( J4 d# 输出修改后的内容
    " |+ l; Q5 I% @( oprint("输出修改后的内容:",tag)
    4 e4 C# X! H& W8 ]. i$ l0 R  M# 获取全部的属性 attrs( J3 d4 N0 Z+ S9 |5 ^, S$ _( ]
    print("tag对象的全部属性:",tag.attrs)   # 只能得到当前标签的属性(不包含下属标签)
    ; M) v( X- L. T- H% s/ O
    6 K& @) ~8 r! J6 N( Z# 获取属性的class的值   根据键取值5 z1 B9 O& l7 e6 W4 ~& f* t
    print("获取属性的class的值:",tag["class"])2 u6 h' u0 Z$ N5 R) X
    - J+ V4 A8 ?, S
    " c5 W; x" `/ w

    ! I* L- ~4 m7 W( q% F) r/ E2 b0 f3 m+ Y) M
    ! ^3 U5 t# ?8 n. [3 W$ i"""针对获取的标签属性可以进行增删改查"""  Q& a" Q3 N+ S. @/ N
    # 修改
    # \9 f2 w; W9 q) D4 Utag["class"] = "Logo"4 H4 I) E( j  ?% W$ Z* o7 g# \) |
    print("tag对象的全部属性:",tag.attrs). J6 y% o* U3 z1 N: S. g# G7 ~
    # 输出属性
    ) u  X; h8 A1 o# \print("获取属性的class的值:",tag["class"])0 W: O4 v3 r* j
    # 新增  属性id  赋值logo
    ) |* Q4 A% P: {( }( e0 U- Otag['id'] = 'logo'
    8 c$ h2 u$ k5 F3 sprint("tag对象的全部属性:",tag.attrs)
    / K8 o! m0 H, J0 Q* f: K# 删除属性
    1 P/ c/ b' z5 A, Odel tag['class']: }  V9 i, x/ l7 L2 s9 E+ T
    print("tag对象的全部属性:",tag.attrs)
    " z4 c% r7 Z" T# p% ^7 v
    4 W; w+ l: o; I& Z4 w8 h+ @5 v2 n3 k# _
    # N- G0 _: r: i+ ^: R
    """针对内容操作  (只针对标签,对属性无效)"""
    # t, ?% O5 ]6 V4 A( N# 获取title标签内容( c, @& _* e9 r4 p5 C7 _% Z' {
    tag = soup.title
    4 s  m- e4 G1 I) j! x5 g# 获取title字符串
    0 t$ Z# r% a5 [1 p9 Z/ Wprint("tag对象所包含的字符串:", tag.string)0 e/ t  ^6 s( g4 m* f2 I
    print("类型:", type(tag.string))' y( v. m6 E. P# l+ y) E
    # 替换内容
    . U* n5 X  _* ~! c6 [4 ytag.string.replace_with("你好")
    , x/ p# c& E  ]2 X( ^9 Y' q. d9 }print(tag.string)
    * N1 ]9 Z+ m, C& e; @- S! N# <!-- 学科建设 -->
    0 }% x7 L( F0 K5 o# 获取注释文本内容- B# \, u) {" V+ N: `
    markup = '<b><!-- 学科建设 --></c>'
    ( w" d3 w  m  O$ w3 M1 ]soup_comment = BeautifulSoup(markup, 'lxml')
    ) n6 `9 M8 f1 K5 a9 n0 C+ W: Wcomment = soup_comment.b.string                    # 以markup第一个标签作为关键进行搜索
    2 ?" z2 h' y3 F; i4 b+ }3 iprint("获取注释文本内容:", comment). K/ e4 O8 X8 S* H* v
    # get_text()
    & m" |" D8 ]! ^. W( e7 _print("title的全部节点:",soup.find_all("title"))$ k$ _! e+ P; ^+ `  U- J3 S
    print("title的内容:",soup.title.get_text())5 j9 k# S" m' M  }" A. L' `
    """查找ul元素标签"""
    : l/ K5 W8 ~! ]. e2 C6 x3 S8 b7 M# class是关键名,匹配时后面必须加下划线_
    1 z& u9 \/ t& l) k- C6 E# tag = soup.find_all("ul", class_='menu')  # 按照css类名完全匹配/ C! ^( [8 b- I# {
    # print(tag)
    / E# M2 K' k: vtag = soup.find_all("ul", id='menu')  # 按照css类名完全匹配
    % ]' ?& X0 D- Y* aprint(tag)$ o; R* {2 P+ s
    # 查找名称为a元素的标签内容
    3 j5 k  a) f% a4 w$ Otaga = soup.find_all('a'). N8 E  s) B# s% D3 X
    for tag in taga:! A, V- l; [% l
        print("查找名称为a元素的标签内容:", tag.string)' O% c0 B, ^: P' H
    # get 获取属性信息  获取整个页面的img标签图片和src属性值( Z* m0 r8 }( }
    tagings = soup.find_all('img')
      k; V) F: l, C) e( o; {) sprint(tagings)* G( |1 R# Q6 J0 g0 w" ~
    # 循环输出图片地址/ M% [6 M' C& H8 u. o2 F
    for imgsrc in tagings:
    3 S3 ]4 y6 H1 F    print(url+imgsrc.get('src'))
    * s' \5 c: B; s4 I0 e3 e" v% x* j/ e. b
    """"属性只能做为参数,所有的操作只能针对标签"""  U7 _3 I: a% j; @( N/ w7 o7 c5 Q

    " t% g+ g" i! r8 Uetree方法:4 S4 Y! Y! a- v
    导入库文件:5 [" j7 C* R' C# s: w1 K
    ) W5 [& d9 i' a3 W) B
    from lxml import etree
    : [  h" Y0 H" h0 V1
    . v6 C, }' \5 b0 b7 p解析得到的response对象;8 s6 P+ }% F7 @" M& K; e

    / j2 `2 [. E/ z, N9 |; n# 设置response的字符集
    4 D, {2 ^! m7 W& _: ^5 P6 Ihtml = req.content.decode('utf-8')9 l- p0 g: a4 H8 ~
    # 解析对象
    $ }' v" V& x" R5 `6 Y  Ghtml = etree.HTML(html,parser=etree.HTMLParser(encoding='utf-8'))& H* \  _# Y; _7 o6 J( i! [
    & c" M" a7 J1 y0 \4 v& u0 a
    常用的方法:7 @" [6 F1 p3 a" |9 G3 ^
    1 {+ E' ~) G- v$ q

    % p" `  [6 g% W: C/ f' ~# 定位head节点(元素)! E9 y) A' y$ D) E2 _. d' w
    result1 = html.xpath('head')
    " ^/ c" L$ r4 E3 X, T) F" C! X& k+ c6 Oprint(result1)
    ) r' g3 p$ j0 ^8 h+ d4 i2 p# 定位title节点
    ( ~# \0 e2 }& v, K( yresult2 = html.xpath('/html/head/title')
      y# H, _1 x( {6 Bprint(result2)
    ' c$ e# V9 l2 f4 J( D* ]& J# 搜索节点  title节点$ @: O/ n7 E; v% b) b+ l
    result3 = html.xpath('//title')
      O2 z. h% D# @$ Dprint(result3)
    # S6 S9 t  p. M4 x5 i7 \+ y( v  y0 u# 搜索title内容  text()得到文本信息
    8 m8 V) f9 v2 E; Wresult4 = html.xpath("//title/text()")
    6 D6 V& ^- J+ e6 sprint(result4)/ l* V! o' R5 H- @5 S) K
    # 搜索div节点% D" q  [; I! I% A* Q
    result5 = html.xpath('//div')2 S  m2 o6 S7 U" v
    print(result5)+ U) s2 l1 a6 t
    # 搜索div节点 并用class属性定位" d% l. C5 q8 r8 {2 R1 n! G7 I8 `
    result6 = html.xpath('//div[@class="news"]')1 ?, a) L  q" M6 q6 s1 q' Z
    print(result6)8 K3 F( m/ ^6 M- e! p
    # 搜索div节点 id属性定位2 I+ K% v7 K$ J2 y- X- w
    result7 = html.xpath('//div[@id="news"]')
    % W4 v2 a1 P0 C" kprint(result7)
    : I; b9 Z6 m- F2 e: ~* G" O# 获取列表span信息9 P" ~# V# o0 W! _- }8 B
    text = html.xpath('//div[@class="news"]/a/span/text()')
    % n& F! \: Y" g" d; L* z  Aprint(text)
    & f" Y5 H+ _! s, F* q0 E% e1 _
    ( `# Z* Y( ^& k0 D  V$ ]8 Q4 e

    g、通过上一步我们得到自己需要的数据后,下一步就是将我们得到的数据进行保存
    2 R) a* T9 [9 L( }5 A保存的方式有很多种:* ~* j$ k; q1 x! \
    1、保存至文件
    3 |3 h. d: M7 Ccsv、json、text4 y" o: {- b! v4 I
    2、保存至数据库; M- o7 A% D$ W  x: r) D5 t( r
    MySql、MongoDB、Redis 等 (目前主流的为以上列举的三种数据库)

    关于数据存储后面再做详细介绍
    * b" M* G9 d# m! L/ n
    $ j2 Y3 p. X9 l1 F, f& \3 \& t2 @! C5 N% G* k7 }
    ————————————————
    6 W. J  r. n1 R! \6 \& e6 ~' \版权声明:本文为CSDN博主「royallucky」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    ( ^6 q( Q' k4 `/ f6 m, C原文链接:https://blog.csdn.net/royallucky/article/details/105930473
    4 p; [8 k3 q  |1 X4 |4 P- ?
    ! Z. \, s1 G0 F$ j7 _2 \3 d! A6 f7 f( B' A! w9 ?! x, S) v1 j
    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-6-14 22:47 , Processed in 0.406346 second(s), 56 queries .

    回顶部