QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 3687|回复: 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
    1 l, ^& G/ _$ a6 d/ f! ^
    3 L1 Q5 W: N1 V4 m. J3 x2 V
    1 D' o; p7 J- X; S
    手把手带你5分钟搞定爬虫(聚焦爬虫)

    ( s3 t1 Q: n4 Y$ q- q+ W5 ]0 B! N# t- b5 N5 d( z3 X5 Z
    爬虫的原理
    : k: k% G2 |" y2 y
    9 t3 N* L9 ~) O- o! C* T* r对于很多刚入门的小伙伴来说,了解爬虫的工作原理是非常重要的。只有当你了解了它的原理,你才能结合实际情况写出对应的爬虫。下面我将以通俗的语言方式来介绍爬虫- `1 I9 q5 B1 ?0 ]! N% Y; B
    把互联网比作一张巨大的网,那爬虫就是这张网上面的一只小蜘蛛,在互联网上面有很多的数据,各种各样的数据,我们可以把这些数据比作是被网粘住的小昆虫等。爬虫的作用就是去找到自己喜欢的口味,然后把它带回家,可以储存起来,也可以马上享受美味- G- M, ~# p# y) w$ Y
    所以说爬虫分为三部曲:
    5 D3 O) A: M' F" f" M7 f+ d5 r1、明确你自己喜欢什么口味(制定需求,明确你需要的数据类型)
    & }0 ?5 a& x1 \( m2、去找到你喜欢的食物的位置(得到目标地址)
    ) G6 r/ R$ e, m6 Z- }0 e6 `3、把食物搬回家去(解析网址,获取数据,存储数据)
    - V- @- A9 A( K1 T( s它的整个流程就是:(简单的通过request请求获取数据并解析获取数据。以下都是固定化格式,可以照搬)
    4 E! A7 f  d7 Z/ X: B! Ba、导入需要的库 requests
    8 |7 [2 m0 i  Y- b: Y0 X, t9 v6 c7 ^  ?' o, h
    import requests3 [+ [* O1 S' I
    1: l* Y0 q# }: m
    b、明确你要获取数据的网址(这里以百度网站为例)! B3 ]- \4 _! i7 `" v
    # N3 v  d9 k$ M
    url = 'http://www.baidu.com'
    $ B7 I# D1 \- L$ x1! T' z- A, w9 p- J. m' `
    c、创建请求  }5 E( Y3 C  b0 Q" W; X+ e4 e  q

    , G* Q! \/ a2 M& m+ Bresponse =  requests.get(url)$ Y4 ?; J8 N  I: N& v" Y* [
    1
    ) m9 Y7 q. Z2 P: O8 ?/ ed、测试请求是否成功(在实际应用中用的比较少,正常情况都是可以请求成功的,网站对于访问外部信息的爬虫是不会做出限制的)
    ! k- ]/ r; z* L) e' {) B+ M8 u4 x+ c2 L: M" k
    print("状态码:",response.status_code): J+ j- X8 J. d8 d
    1
    2 I$ f$ n! l/ C0 O; J! c6 d当状态码为“200”时表示请求成功;如果不是“200”,很大可能就是你的目标url写错了,核对一下url) J! \7 n6 x! @. L( G' ^
    e、得到网页源码  R& d6 j4 m* D+ f% I8 ?" k

      {! D7 z: O) _2 j/ v( o: {print("内容:",response.text)
    ! B% h1 f$ I8 L  w. [+ z  h11 T1 ~/ s' Q* c- P6 {7 T# ]: G1 f
    response.content是response.text的二进制形式4 j0 Y+ K6 j/ S: X  d' Z

    & m! t$ @' b' A1 j. _, x9 R至此,一个简单的爬虫请求就算是完成了。/ x1 p4 w7 O) W, N
    当我们请求目标url并获取到response后,就需要进行下一步:解析网址并获取数据/ ~; R; t% j9 G. Z$ o' `
    f、解析网址" s6 |; G0 }  h' c+ Z
    刚开始学习阶段,我们最常用的两种方法,一种是BeautifulSoup,一种是etree。其中BeautifulSoup是最常用的。以下将对两种方法分别进行介绍 (以下方法均为测试用例,实际当中应结合自己的实际情况选择应用)  T1 a( n' P+ z8 V
    BeautifulSoup:
    9 |% k- ~4 {. w9 R2 z4 ]首先导入需要的库文件:
    & B# G: t3 b7 f
      I! ]. F: w0 g4 h" vfrom bs4 import BeautifulSoup
    8 ~  F" e: U  J$ M/ _1- E; r# ^1 a; i9 _" {7 I
    然后对上面请求得到的response进行解析:
    8 z6 e4 a/ U7 j- A5 H& J9 @: k5 H" B$ D& B; e( X
    html = respone.content.decode('utf-8'). w. u6 r+ c; D) A' S
    soup = BeautifulSoup(html, 'lxml')
    2 ~! u  ~/ Q2 j: P' j- K1
    3 d3 T+ {% o# ?! i* U: V2
    & ^% T8 c5 V+ _% J以下是BeautifulSoup中比较常见的方法,有兴趣的朋友可以去一一测试:
    0 x3 O. u2 f+ C. F5 Q* k# 获取head标签8 m. p/ i" K) W' u- L8 m
    print('head标签内容', soup.head)
    $ N  _; J$ |1 s2 ?: e$ W# 获取title标签
    4 j, Z& u4 K8 j' T" O( ?print('head标签内容', soup.title)
    ' C! m2 E2 G3 l# 获取body里面的img内容
    9 \8 n2 g, C0 e2 P" m0 B# 通过点号的方式只能获取 下属第一个标签(即获取soup下面第一个body里的第一个a标签的第一个img标签)
    3 N* x+ A3 q: ?6 k& Pprint(soup.body.a.img)   
    6 z; i+ e5 }' }, t# 获取所有的img标签  使用find_all()搜索整个soup对象
    8 h# }# A6 d* q; [& }7 Eprint("获取所有的img标签", soup.find_all('img'))
    / e  _, b0 }( J# 获取标签中的属性src地址
    + b: j) Y* g8 C+ ?7 O. Zprint("获取标签中的属性src地址:", soup.img['src'])      # 注意:英文点号都只能获取第一个值: m8 v1 k3 ^! U) G  o+ C" Y& j

    0 Q  i( y7 Z: n  s+ @4 A- _. y* S/ |6 q. R
    # 获取soup的name
    5 |( B! Q1 z: F4 a7 {( z! v% Nprint("获取soup的name:",soup.name)
    6 n  v) U* g4 F# h4 X2 C% u# 获取a标签名
    0 D2 G; L& p( Vprint("a标签名字:",soup.a.name)
      N& M7 l" `0 C& l; {2 {) v7 rtag = soup.a
    $ ~5 Z/ D& r/ ~$ ~4 ^+ k8 j7 jprint(tag)7 i& [( H0 T' K9 U
    # 修改操作  a标签改为b标签
    " f5 p. n' p' J# H1 ~2 w9 rtag.name = 'b'   # 赋值后<a> </a>变为<b> </b>
    + b% I  B/ H( R5 n/ i, F- r, z5 N7 Z# 输出修改后的内容( q) _) ^" U4 N8 d: s
    print("输出修改后的内容:",tag)0 x0 T  @! f$ @
    # 获取全部的属性 attrs
    6 {0 w1 v5 Z# u* v0 {% fprint("tag对象的全部属性:",tag.attrs)   # 只能得到当前标签的属性(不包含下属标签)
    & i' b3 ^$ L$ U0 T+ |) B* r" L' K3 V+ Q$ B5 @6 [. a' y$ [) c9 m8 z5 c* Y
    # 获取属性的class的值   根据键取值3 {$ l  B6 N# [6 W  z
    print("获取属性的class的值:",tag["class"])
    ; r9 p' V4 l  ~" y. x' k  z. A1 D* E1 \& Y- V9 x9 w

    5 V8 J: [6 o% t* {- G
    , n5 C& M! t* F9 h6 Q* Q+ W, |, }$ z% I2 }
    """针对获取的标签属性可以进行增删改查"""4 z' o* ~7 G. U) Y
    # 修改4 l! j3 c- ~7 g$ v1 g7 E1 K  V
    tag["class"] = "Logo"$ ]2 b* g* t1 ~+ z
    print("tag对象的全部属性:",tag.attrs)& ], m3 i( R' L4 v3 |. G* M
    # 输出属性
    1 e0 O2 j& e/ \& T1 P% f% w  fprint("获取属性的class的值:",tag["class"]): ]: I6 E& m' E. T) E* x: o( z
    # 新增  属性id  赋值logo0 l9 k! N* N. c+ G8 R! L0 X
    tag['id'] = 'logo'  _6 [& }7 @4 c# |( l
    print("tag对象的全部属性:",tag.attrs)
    + X) y% t! r$ B# 删除属性
    : M# r# t% m$ J7 ?0 {del tag['class']
    4 H; T% Q9 ]' R4 I: pprint("tag对象的全部属性:",tag.attrs)
    4 I: a& @  G6 K; d0 X" o0 _/ }/ z- Y+ G  R; u

    9 R- c& R- W$ L" A1 q; R2 Y0 ?2 \3 t% v, ~4 F! O5 \' h+ z. [% f
    """针对内容操作  (只针对标签,对属性无效)"""
    % i3 r% z, Q8 d# 获取title标签内容, p. {/ x  O# E7 L
    tag = soup.title
    9 y5 r2 Y* n: u7 h8 i9 \/ \# 获取title字符串; D1 G' L( J+ c$ _
    print("tag对象所包含的字符串:", tag.string)3 O* U! I' M3 Z5 g
    print("类型:", type(tag.string))* {+ X" K1 R: `8 O2 ?& X
    # 替换内容. ?( C8 b1 v# T) {. B  p
    tag.string.replace_with("你好")$ [/ k8 r2 [2 [# R6 o9 X! F6 J
    print(tag.string)- ^( j- T; V+ b1 q8 O
    # <!-- 学科建设 -->
    " b  A& \4 \* g7 f. {1 A  I# 获取注释文本内容
    5 ?# B1 g2 |3 [' |2 \markup = '<b><!-- 学科建设 --></c>'9 d3 f5 Z9 e. H: w7 s6 Y) G- y
    soup_comment = BeautifulSoup(markup, 'lxml')+ A) x; c+ w" |! D
    comment = soup_comment.b.string                    # 以markup第一个标签作为关键进行搜索
    : p" n8 C: D1 J8 X7 O  A, iprint("获取注释文本内容:", comment); `+ [! D0 B& x  U# f3 n
    # get_text()
    - t6 k; c+ Y( @* w$ B. a* ], h( Tprint("title的全部节点:",soup.find_all("title"))' K! g4 D3 `% W! V0 ^) q' I
    print("title的内容:",soup.title.get_text())
    8 B/ P3 [3 X5 ?! m"""查找ul元素标签"""! o  n2 V1 r) s$ K4 v1 V
    # class是关键名,匹配时后面必须加下划线_
    $ g) T) \( _9 @+ P3 l9 u# tag = soup.find_all("ul", class_='menu')  # 按照css类名完全匹配6 f' N8 i. Z/ Z& d$ @4 \* E5 o, B! R6 o
    # print(tag)
    ) |) Y7 \6 w, p1 A2 X# M9 z, otag = soup.find_all("ul", id='menu')  # 按照css类名完全匹配/ a2 v! B1 [+ I- l7 ^6 V- b
    print(tag)
    . e& N- e6 Q; k7 A3 _1 {# 查找名称为a元素的标签内容
    / [' [; K  B, |; x, ^taga = soup.find_all('a')7 J- |5 N8 Z4 |" Z: _$ D
    for tag in taga:9 O/ z9 w# @& b& @; f
        print("查找名称为a元素的标签内容:", tag.string)
    * s+ Q8 p' B4 V: F  b! W# get 获取属性信息  获取整个页面的img标签图片和src属性值+ g0 O- `! W9 @4 E! v) M
    tagings = soup.find_all('img'): r. B% T* g; Z8 r* Q
    print(tagings)7 c$ Y1 o) b$ `" h$ l$ h; w
    # 循环输出图片地址
    # ?# @8 u% j% A1 i; Sfor imgsrc in tagings:
    + m8 ]3 t9 j* q$ C    print(url+imgsrc.get('src'))
    ( l' N- B' C* s8 `- s/ C- h4 |
    2 d' m# {/ O* L3 l+ j/ `& W& R""""属性只能做为参数,所有的操作只能针对标签"""
    9 v$ V8 p% T2 f8 m# T# I$ {" ]( v# R7 l" u% q9 ?, X% c6 w1 Z
    etree方法:
    1 ]2 z/ ?; O* ?, G- T6 e1 D- s导入库文件:- [4 k4 r4 |4 l0 A0 j

    ! ]1 Q* u5 }" w$ C4 O/ B* ?from lxml import etree7 F( |9 Y  e5 Q
    1! Y3 a+ \0 `' C7 S8 W
    解析得到的response对象;
    5 L2 ^# D) L9 u( H
    ' A8 V" s# q- @- a! ]' \% B# 设置response的字符集
    , ~8 \) N4 u( m, x: yhtml = req.content.decode('utf-8')
    # C8 X+ V9 `$ q& T, M# 解析对象& B2 ]) b7 s" H+ z2 Q5 V
    html = etree.HTML(html,parser=etree.HTMLParser(encoding='utf-8'))5 c* d' H  i; G3 K7 F  F
    5 U9 a  m7 M! [: r1 ]8 s
    常用的方法:* p0 M# O. c1 O/ c+ p* V5 ]& t
    " B! h1 p0 p+ |% y5 Q1 y% x

    # ]: h( J: t# M# 定位head节点(元素)
    8 d  z" S' ]% e: S9 u/ Yresult1 = html.xpath('head')8 C5 N: ~) Q% F
    print(result1)) o( P9 z  n2 }0 l
    # 定位title节点
    9 u" g7 O  O. B4 mresult2 = html.xpath('/html/head/title')
    3 Y9 {# h4 d2 l0 b" Kprint(result2)0 q1 ]4 S+ F# P
    # 搜索节点  title节点+ a5 P- F$ X& r7 ]. o9 y6 p. j9 {6 E0 |. a
    result3 = html.xpath('//title')8 q3 }& K( |8 {, h% F1 V
    print(result3)
    ; p5 [% l! M- O2 m3 ?0 n+ ^5 K' M# 搜索title内容  text()得到文本信息
    / ~# X* F! B1 d$ o1 A4 Tresult4 = html.xpath("//title/text()")# {& |7 L# k# |+ W" R4 @% {4 c
    print(result4): g7 M- z. r% [$ d
    # 搜索div节点! T" Y. g( f! Z3 k
    result5 = html.xpath('//div'), B# K7 v* t; [! i0 x* U
    print(result5)
    0 Z) u! `6 t  w; b# 搜索div节点 并用class属性定位+ K! n) @. `2 j% O) h% b
    result6 = html.xpath('//div[@class="news"]')# G; w1 c- o' Z% U) E
    print(result6)
    * }2 \( v( B7 b' C: Y# 搜索div节点 id属性定位2 N; o" D) H$ N
    result7 = html.xpath('//div[@id="news"]')
    9 ^0 S( O3 T+ r3 Cprint(result7)9 c# D' c$ z* ^* H2 O. q. w) h
    # 获取列表span信息
    ; O, i) J, P$ B/ d1 E3 }' ^text = html.xpath('//div[@class="news"]/a/span/text()')( t( {4 l7 g3 B5 ]( J# t% w
    print(text)
    9 E* a/ N! s2 f& q
    ; T+ g# E; }$ ~

    g、通过上一步我们得到自己需要的数据后,下一步就是将我们得到的数据进行保存. r9 B  t3 d7 C# F
    保存的方式有很多种:! _' J9 y/ B9 M2 ~  A3 J
    1、保存至文件
    ; q- ~/ G5 o' Z% acsv、json、text
      Y3 b/ s: h+ I2、保存至数据库
    # s7 P5 y0 b6 y: G1 }MySql、MongoDB、Redis 等 (目前主流的为以上列举的三种数据库)

    关于数据存储后面再做详细介绍
    * p: l- t* f$ b3 n5 r
    * }6 V3 f  q: I
    $ U4 _+ A3 g4 N& B' w5 E————————————————8 @3 t7 b2 J& `) y: u2 o' b7 a
    版权声明:本文为CSDN博主「royallucky」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。$ U* x7 V  B2 {# B( G
    原文链接:https://blog.csdn.net/royallucky/article/details/105930473* j2 r( k) f; ^: e) u: u. ?

    ' o" ~! v! z' X2 Y0 K
    + p2 T* R  E' `
    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-5-27 13:29 , Processed in 0.500270 second(s), 56 queries .

    回顶部