QQ登录

只需要一步,快速开始

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

    * I1 S8 e3 r+ ~) w1 C4 ?9 e
    / c4 x7 s, v5 n% t

    % U7 f2 }$ w1 Z
    手把手带你5分钟搞定爬虫(聚焦爬虫)
    , j, L5 Z2 w  Y5 |* Z
    % w; N; T! z# V( w. v; l
    爬虫的原理
    9 ?; u* @0 C; P5 S& e3 ]
    / D1 Q+ t/ z+ @1 t! D* m( \对于很多刚入门的小伙伴来说,了解爬虫的工作原理是非常重要的。只有当你了解了它的原理,你才能结合实际情况写出对应的爬虫。下面我将以通俗的语言方式来介绍爬虫# e' b+ z# o1 r+ H; m! w' _; g
    把互联网比作一张巨大的网,那爬虫就是这张网上面的一只小蜘蛛,在互联网上面有很多的数据,各种各样的数据,我们可以把这些数据比作是被网粘住的小昆虫等。爬虫的作用就是去找到自己喜欢的口味,然后把它带回家,可以储存起来,也可以马上享受美味
    5 z2 t7 D6 y; A3 z+ L所以说爬虫分为三部曲:
    ' H1 h4 q- Y$ E7 `# h- w! @1、明确你自己喜欢什么口味(制定需求,明确你需要的数据类型)
    , y, H1 B! W' h% y: ^# Y6 Q2、去找到你喜欢的食物的位置(得到目标地址)0 l. ^+ ]5 f3 O4 |7 e
    3、把食物搬回家去(解析网址,获取数据,存储数据)
    # b2 z$ N! q, [5 W它的整个流程就是:(简单的通过request请求获取数据并解析获取数据。以下都是固定化格式,可以照搬)9 X0 ^8 z1 R. |; j
    a、导入需要的库 requests
    0 n9 J: c* \% l
    & E1 `- r4 w' w$ `import requests; A6 R0 q! K/ S  D$ ]: x6 A
    18 |9 L. w9 k+ `5 l2 m
    b、明确你要获取数据的网址(这里以百度网站为例)2 C# U# L  J0 \. _* k
    : _0 \7 Z+ h( g1 @7 g: ]6 o9 S
    url = 'http://www.baidu.com'
    $ \! J7 h8 W7 v0 G" x/ j1
    8 M& T' g" I/ P  N, J9 E. R" \c、创建请求
    % T" x+ H0 A8 @: L7 p8 B$ C- [% K
    response =  requests.get(url)
    ! Q  J# v9 a* t# E* _0 b4 D11 O$ B7 T3 s: T" s
    d、测试请求是否成功(在实际应用中用的比较少,正常情况都是可以请求成功的,网站对于访问外部信息的爬虫是不会做出限制的)
    6 ^2 {) z! ~. T3 |% X% w9 l% T! ?4 C7 Q3 z$ ^9 N
    print("状态码:",response.status_code)
    / O2 F2 m; m2 H- P) G. t4 p& y1
    0 n' f5 p9 ~! T! Y当状态码为“200”时表示请求成功;如果不是“200”,很大可能就是你的目标url写错了,核对一下url
    9 y2 S3 ^& I" G7 U: j) \! W% Ie、得到网页源码
    # a$ u; M  e) V) P* a
    7 S! E* G( c3 a6 b! Dprint("内容:",response.text)
    ) P/ F( d; w8 L; B- Q1! Y( b1 ^- c- S8 k
    response.content是response.text的二进制形式
    * F: W4 G6 l! ]# X' E, l
    & S4 ~: g1 f0 P至此,一个简单的爬虫请求就算是完成了。
    ! ?, |  P0 R' ]: |$ t) t, `3 j当我们请求目标url并获取到response后,就需要进行下一步:解析网址并获取数据
      O% [) f1 m  r& r6 {f、解析网址0 i1 D: X$ s1 E
    刚开始学习阶段,我们最常用的两种方法,一种是BeautifulSoup,一种是etree。其中BeautifulSoup是最常用的。以下将对两种方法分别进行介绍 (以下方法均为测试用例,实际当中应结合自己的实际情况选择应用)) ?% u1 ]$ y6 v9 d( z+ {9 u
    BeautifulSoup:
    & U3 C' @$ ^/ X8 j, A- A首先导入需要的库文件:
    4 [0 P8 T" x2 C' j2 t) g* f: g% {1 ]# V3 q- ?, D
    from bs4 import BeautifulSoup
    5 E1 j" `, ?% u5 b# W1
    8 M$ S' b. \& D然后对上面请求得到的response进行解析:6 e: ?# e- Z, v& X" Y
      g0 t$ T: ~( d- L  Z! E
    html = respone.content.decode('utf-8'): d# c4 X& R* ^! B
    soup = BeautifulSoup(html, 'lxml')7 g. g( N" t  P! O2 G
    1+ x2 ^4 S" h  W, F
    2  |6 ~: N( ~) ]3 k. H
    以下是BeautifulSoup中比较常见的方法,有兴趣的朋友可以去一一测试:
    8 _% l& j. ?! C. e# 获取head标签% W) K# W: _9 ?4 t: t# m: v- r+ E
    print('head标签内容', soup.head)4 U+ O" |6 H4 Z7 Y0 _$ b
    # 获取title标签/ U2 N5 u1 X* \  c: a
    print('head标签内容', soup.title)
    & `0 r2 a- O6 r6 u: S- e# 获取body里面的img内容7 r2 s' `/ W# s% c! ~5 L
    # 通过点号的方式只能获取 下属第一个标签(即获取soup下面第一个body里的第一个a标签的第一个img标签), g, c/ L* A2 m' i( d. W
    print(soup.body.a.img)   
    6 M( `. E2 ~/ q# L$ Z+ R# 获取所有的img标签  使用find_all()搜索整个soup对象
    & r: P% p# Z7 d' a, G2 H* u; ~1 Yprint("获取所有的img标签", soup.find_all('img'))
    . O' D2 n! y5 T8 h1 {- A8 s$ B# 获取标签中的属性src地址
    & m" N, N# h( a! `% H! X5 H- r. M0 q/ wprint("获取标签中的属性src地址:", soup.img['src'])      # 注意:英文点号都只能获取第一个值/ g! t+ v  a5 b7 G; ]/ E0 j
    * E& e1 r! q. ?$ P, U4 w
    & ]( q) J; Z7 z2 m1 {
    # 获取soup的name! f6 G" d; N  f! S  o
    print("获取soup的name:",soup.name)
    * u* o6 ?1 x9 i# 获取a标签名, n) E+ j! h3 T& I' X
    print("a标签名字:",soup.a.name)
    ) O& u8 O! e9 F4 l6 Vtag = soup.a( z+ C1 K2 q1 d# `! p9 V
    print(tag)" U8 [$ [2 `. o6 Y/ M! l: f% D
    # 修改操作  a标签改为b标签
    ! c. p  B; d. ptag.name = 'b'   # 赋值后<a> </a>变为<b> </b>2 W8 s" m9 Q  |; d! s/ Y- W5 O1 u
    # 输出修改后的内容4 K+ q5 z, }2 p, p# D. T6 ]+ i! @
    print("输出修改后的内容:",tag). E2 l, r- N7 r
    # 获取全部的属性 attrs
    , g3 U& a0 X) qprint("tag对象的全部属性:",tag.attrs)   # 只能得到当前标签的属性(不包含下属标签)( i) D  |; X2 q* B+ T

    & M$ g  a" O: c" V# 获取属性的class的值   根据键取值
    6 r& L/ M( {- P0 Q5 {print("获取属性的class的值:",tag["class"])6 s- W* O, f5 t$ o/ U! ]

    9 H. a/ E) t) {6 T3 \) k  V+ ]5 a
    ) r( h/ m: c) J6 T
    " I6 D8 b) E2 b8 C0 b, V: d. S9 E3 l: ^0 N% T) E
    """针对获取的标签属性可以进行增删改查"""
    6 K! S4 p$ V9 E9 j9 O3 P# 修改
    ! I! Q( ?9 V. j, C/ H+ |tag["class"] = "Logo"
    : ~0 F, n% q; `print("tag对象的全部属性:",tag.attrs)5 j, c0 m! C( h
    # 输出属性
    ; T7 Q& u2 V2 n5 K6 yprint("获取属性的class的值:",tag["class"])
    ; _# a- U. z5 T8 L! ?# 新增  属性id  赋值logo
    5 ]8 M, g! E! I+ dtag['id'] = 'logo'2 @1 H  b" M0 e; t5 _
    print("tag对象的全部属性:",tag.attrs)
    # z+ q& b: X9 n# 删除属性
    0 g7 _. Y( i6 z, I& Jdel tag['class']* a3 Q6 H' j) o* s" _- t- Q
    print("tag对象的全部属性:",tag.attrs)) z; p" h+ z# s" p+ H# T4 ?
    - G  c" H" V% T: U8 t9 J
    ) n6 K( w. o) V# Z9 }, i

    1 B" S' P3 I! G2 o; V" v( w"""针对内容操作  (只针对标签,对属性无效)"""* t% U6 ^4 k7 G) b
    # 获取title标签内容
    ' }2 U# k; u" O- B. D1 Htag = soup.title9 Y$ c; h/ C+ e& g, H/ q
    # 获取title字符串
    + s% ^# i- s; C$ [' y* A% B) K1 qprint("tag对象所包含的字符串:", tag.string)2 v9 v2 i  w2 s4 u* N
    print("类型:", type(tag.string))* z: C- u. x3 l  _$ a  T
    # 替换内容
    1 F% [5 G8 U$ z& J1 b, Htag.string.replace_with("你好")  G, c' K2 z6 y) Q4 F! `. I. B
    print(tag.string)
    . R( O' z$ w0 k$ A, P: p# <!-- 学科建设 -->
    / d* T- `5 A- B. A# i# 获取注释文本内容
    9 Y3 h! g1 j/ k& ]markup = '<b><!-- 学科建设 --></c>'  y2 l/ m' Y' d/ S+ p2 X2 P
    soup_comment = BeautifulSoup(markup, 'lxml')$ U3 p  o! J9 S3 I
    comment = soup_comment.b.string                    # 以markup第一个标签作为关键进行搜索
    , w8 N9 A  y) x! y) O+ Vprint("获取注释文本内容:", comment)
    8 t" @$ r* d! S1 {: S$ B6 e3 E7 r8 x# get_text()
    $ z- N+ M& L  Q  J: T+ ]print("title的全部节点:",soup.find_all("title"))% Z6 `! \7 t+ [% x. l, Z7 C! {
    print("title的内容:",soup.title.get_text())
    . ?& l) E$ R& [: J$ L"""查找ul元素标签"""' A9 j% c! m9 S8 s$ Z
    # class是关键名,匹配时后面必须加下划线_. x# C8 T4 g! T9 Y' ]& T8 s( b
    # tag = soup.find_all("ul", class_='menu')  # 按照css类名完全匹配
    5 f$ ]! _: L3 o; N& }& Z# print(tag)
    . @7 ~: u  d" N, N# w- M" p$ c& Mtag = soup.find_all("ul", id='menu')  # 按照css类名完全匹配
    0 r) P5 S5 `/ Q! s3 ~4 rprint(tag)3 f. X4 e: U1 i# U9 |' S: e8 _
    # 查找名称为a元素的标签内容
      _& \1 B+ z. L: dtaga = soup.find_all('a')
    / A+ ^0 h  ]" t  S* I1 N1 J3 r+ pfor tag in taga:
    6 I$ d+ n, x( j) B    print("查找名称为a元素的标签内容:", tag.string), r, _( L8 L. K+ C9 f
    # get 获取属性信息  获取整个页面的img标签图片和src属性值
    % N- F5 b) g5 @* t& ?  Dtagings = soup.find_all('img')
    5 N/ R6 x. `: x- L7 [3 n. K% kprint(tagings)4 F0 G" m* k1 ]- Z- z) w* K1 \& `
    # 循环输出图片地址
    . t0 ~2 L/ I- n. h+ {for imgsrc in tagings:5 W# G9 U) }9 H- p$ F
        print(url+imgsrc.get('src'))
    ; I7 \: F8 L4 s. H8 c, j- Q, }# R* u9 p" o0 e/ p; w+ U
    """"属性只能做为参数,所有的操作只能针对标签"""1 J* U/ `+ b0 E9 U$ m( T" t4 U9 N4 }

    # C. _+ t3 k8 |0 h7 `* w/ m6 cetree方法:: `/ P- k* Y. D. l8 g$ W) f
    导入库文件:9 g, e, h& d8 }3 ^. s* H0 I2 D

    + |( \* R- T& g: Jfrom lxml import etree3 w, b) S% u5 ~0 e
    1* P6 @. ?( ?# C! {. X8 D( s1 C/ L
    解析得到的response对象;
    5 K% u0 X3 n) x! V' j' ?7 b+ q9 z' K2 |
    # 设置response的字符集
    / l! S% |4 R6 G6 I2 Vhtml = req.content.decode('utf-8')
      m5 S- V- |7 ^8 ~: a/ l# 解析对象) S- h8 e  t5 W: I! h
    html = etree.HTML(html,parser=etree.HTMLParser(encoding='utf-8'))
    4 M/ w9 Y  @+ {
    8 `! X; G$ u: L& ~+ |  D常用的方法:0 y1 @, ?$ v* l/ [5 }' l

    ; c( F  k. _/ i. f, C
    ! \+ W1 ~+ H# _8 L7 ]# L/ E  Z# 定位head节点(元素)
    4 z) \: a0 u$ S+ G4 lresult1 = html.xpath('head')
      O( |4 ]( D- `3 R- vprint(result1)  d: r6 T1 ^/ w' K
    # 定位title节点
    5 Z- f5 ?" M0 ?! a" |) ~result2 = html.xpath('/html/head/title')# Z- L+ P7 \; N# [  ]
    print(result2)% q8 Q: L  F4 l
    # 搜索节点  title节点
    % b3 k4 U6 h! U9 E/ Nresult3 = html.xpath('//title')7 Z% @% L: w! b* s
    print(result3)
    " i4 g9 q* c7 S# 搜索title内容  text()得到文本信息: }; N1 X- y2 M% m. ~
    result4 = html.xpath("//title/text()")+ {0 N: O5 W$ b, z$ j+ J
    print(result4)% U% w( Z/ }) ~
    # 搜索div节点% f$ t0 k; ^' U# f9 a
    result5 = html.xpath('//div')
    . {& s) ?7 M4 y' ?0 eprint(result5)
    & {8 ^& K8 M7 C8 j$ Q* {# 搜索div节点 并用class属性定位
    ' x9 @4 X: p. o8 j4 z$ Jresult6 = html.xpath('//div[@class="news"]')/ K/ U9 T, k; P
    print(result6)/ ^+ h- e7 o( K) X2 H
    # 搜索div节点 id属性定位
    . ~. ?) l1 {' h# w- d, i& tresult7 = html.xpath('//div[@id="news"]')
      [- Y+ A6 o; Yprint(result7)
    2 |8 r. Q1 S; P9 R$ U( \8 y# 获取列表span信息
    6 g% Z, m3 T8 H7 B; h7 @text = html.xpath('//div[@class="news"]/a/span/text()'). j% v5 O# s& P0 `7 G) b  ~+ G
    print(text)- c' f6 @. S/ f4 I+ Y! i$ M2 p

    1 \+ i5 A' p6 [; @# H

    g、通过上一步我们得到自己需要的数据后,下一步就是将我们得到的数据进行保存/ v2 T4 B/ M8 w' k
    保存的方式有很多种:
    4 Q) `3 D8 c# {' C1、保存至文件
    3 a3 p* U0 g$ i  {8 Vcsv、json、text) T' Y6 K4 A7 n% H
    2、保存至数据库; A' t0 F6 [9 s% b& ?. ?3 h
    MySql、MongoDB、Redis 等 (目前主流的为以上列举的三种数据库)

    关于数据存储后面再做详细介绍0 I6 z4 h8 o- e8 X7 d, h. l
    5 ?2 f+ G4 z0 U
    ' m1 a) k4 j2 V0 p+ \
    ————————————————) Y' ?1 H! m3 H( D* \
    版权声明:本文为CSDN博主「royallucky」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    ; j7 T+ I( i8 C* w* u( d) T/ |4 w原文链接:https://blog.csdn.net/royallucky/article/details/105930473
    ! y2 [! J( ~- Z- w# s; e' {
    5 l  S- V' |9 A$ x% t. y
    6 b7 w- ^/ x) c3 S; j3 S# t: \
    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-15 10:17 , Processed in 0.432517 second(s), 56 queries .

    回顶部