QQ登录

只需要一步,快速开始

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

    ' B7 t& O# E# C0 M, w+ b5 w/ g

    6 o& N, \- r- \% ]. f: o
    % ?/ N- O) @3 T$ r5 q; @9 V# ^! ?
    手把手带你5分钟搞定爬虫(聚焦爬虫)

    6 R) @9 i" J( f$ p
    ( V! g7 j; V: o7 X( n, B爬虫的原理
    1 j4 r$ r! O/ C6 H, }- x' H1 D6 C. I* u* h/ q/ w$ C! A
    对于很多刚入门的小伙伴来说,了解爬虫的工作原理是非常重要的。只有当你了解了它的原理,你才能结合实际情况写出对应的爬虫。下面我将以通俗的语言方式来介绍爬虫1 Z* k1 _# M- [2 A7 J5 l) V! R. M
    把互联网比作一张巨大的网,那爬虫就是这张网上面的一只小蜘蛛,在互联网上面有很多的数据,各种各样的数据,我们可以把这些数据比作是被网粘住的小昆虫等。爬虫的作用就是去找到自己喜欢的口味,然后把它带回家,可以储存起来,也可以马上享受美味  |1 R  W6 F5 M! i6 O  w: C$ v, v
    所以说爬虫分为三部曲:8 A) `+ h( c; H2 F* Q4 X7 f
    1、明确你自己喜欢什么口味(制定需求,明确你需要的数据类型)
    $ R- W5 J" M9 r' z- w1 _. T+ X2、去找到你喜欢的食物的位置(得到目标地址)4 p; q+ S5 x' F  y# x; |. J
    3、把食物搬回家去(解析网址,获取数据,存储数据)
    6 m; e  z4 F* p" o4 E它的整个流程就是:(简单的通过request请求获取数据并解析获取数据。以下都是固定化格式,可以照搬)0 H& N7 v3 o! _' i
    a、导入需要的库 requests
    7 p2 Y' C: \4 K# Z- V5 g% i- u  S% T1 S& T* h2 j
    import requests" N; Y, h. |. C6 X9 b4 i
    16 V) S+ x* l  p  b% l
    b、明确你要获取数据的网址(这里以百度网站为例)
    . H* Z5 y8 S" @" C
    6 C/ c, U# O; t4 w6 d) `9 t' i: g$ k! c9 aurl = 'http://www.baidu.com'
    " K1 W0 k1 i6 N* O1
    ; _& {& T% G) j- \; p$ K% N) lc、创建请求. K) {% r, }2 i
    3 }: J3 R: c! c
    response =  requests.get(url)
    ) ^, c8 V/ B: ?5 b2 H1 f: H0 l1
    5 j5 u2 s6 ?* V, E& F- O/ gd、测试请求是否成功(在实际应用中用的比较少,正常情况都是可以请求成功的,网站对于访问外部信息的爬虫是不会做出限制的)1 w2 f9 k1 P4 B& f1 X0 C

    # j/ l) A7 y, h3 [; |5 M' t# Zprint("状态码:",response.status_code)
    : Y& B- B/ M4 H" e6 }+ m1- P; O& }8 Z& D& _1 s( X
    当状态码为“200”时表示请求成功;如果不是“200”,很大可能就是你的目标url写错了,核对一下url8 S$ v; t. x$ P& W$ b3 H
    e、得到网页源码
    7 s3 ?8 K; l: G% M5 w- V' R0 v( u  N0 {/ o) \& c9 g3 C
    print("内容:",response.text)
    3 i5 }! X* Q+ b  m3 r  s1& T5 E) E3 W, m" J+ M% @
    response.content是response.text的二进制形式
    8 c9 z4 e) l% T) z7 A9 f' P1 L1 D
    4 g6 }2 G7 C9 R$ S* s3 [5 Z至此,一个简单的爬虫请求就算是完成了。4 W6 f% n9 q% k; X" _
    当我们请求目标url并获取到response后,就需要进行下一步:解析网址并获取数据
    $ _4 g  E. L, M* R; M3 q& Jf、解析网址" C0 i) n  T1 g; s: J
    刚开始学习阶段,我们最常用的两种方法,一种是BeautifulSoup,一种是etree。其中BeautifulSoup是最常用的。以下将对两种方法分别进行介绍 (以下方法均为测试用例,实际当中应结合自己的实际情况选择应用)6 d5 W: O6 g' a6 }& d# @  y
    BeautifulSoup:
    0 W8 K  @9 r  l) {7 D& H首先导入需要的库文件:
    " ^6 s" m) c5 F  R$ O% q# z& M' U$ h+ E7 B: a
    from bs4 import BeautifulSoup# \; V/ u3 }& Q  i4 g7 u/ q
    1
    / K; e5 y9 D- X$ @; y- H3 D# \然后对上面请求得到的response进行解析:
    , v; ^+ X( o/ C3 a( p$ j5 P1 d7 y( y" K/ X% Q- L+ I7 Q
    html = respone.content.decode('utf-8')
    : F' y5 N! K" M* ^2 B7 usoup = BeautifulSoup(html, 'lxml')
    ! Q3 }1 Z- ~$ ^" [7 {3 ?9 j, O4 f' R1
    1 x3 S9 Z9 C+ |. K21 \2 V$ ^3 C% G
    以下是BeautifulSoup中比较常见的方法,有兴趣的朋友可以去一一测试:
    1 N8 e- u3 e. @6 I8 @: K+ ]# 获取head标签7 z6 C3 {0 i+ _
    print('head标签内容', soup.head)
    ! y" O! a4 t- g# Y8 @# 获取title标签
    ' h3 ?* n; u5 Q- R2 a6 Y  p- Dprint('head标签内容', soup.title)' t% g- E7 M. {0 N6 R% ?: s
    # 获取body里面的img内容+ x' K, V% {; Z8 m' q
    # 通过点号的方式只能获取 下属第一个标签(即获取soup下面第一个body里的第一个a标签的第一个img标签)
    & v, Q$ {  Y( Z. R. F  A3 c* sprint(soup.body.a.img)   
    3 @5 N+ ?6 j6 c# 获取所有的img标签  使用find_all()搜索整个soup对象' q) E4 o+ n' b3 z& h% Q
    print("获取所有的img标签", soup.find_all('img'))/ U6 Z/ L4 u9 K. O8 \9 L
    # 获取标签中的属性src地址& U  ]+ Z) I0 H  b  C
    print("获取标签中的属性src地址:", soup.img['src'])      # 注意:英文点号都只能获取第一个值; V. |' J; _$ @: e7 c7 C; H. e7 [+ G0 Y
    / A  q3 c! p3 X" k8 E3 p' T

    $ U4 j5 }9 x! T# 获取soup的name9 i" F3 a6 @2 s  e4 \
    print("获取soup的name:",soup.name)
    # |# p6 y# ^' Y4 o# G# 获取a标签名2 T3 d* b) U0 _
    print("a标签名字:",soup.a.name)$ n6 W/ I# Q6 k% j
    tag = soup.a
    ' H7 K& v2 U& E4 u+ |1 ]  }, xprint(tag)
      o/ b% k: `  R3 m6 G4 [, T# 修改操作  a标签改为b标签% k8 H9 M& x; b  A# N' O* |
    tag.name = 'b'   # 赋值后<a> </a>变为<b> </b>; K5 ^+ C) Q: z7 E8 m+ c$ N
    # 输出修改后的内容' B' Z$ B$ K) b% g; ~6 U
    print("输出修改后的内容:",tag)9 T5 ^8 b6 Z: R$ d; Q" q
    # 获取全部的属性 attrs
    9 f  O& r9 h6 |9 B5 D3 U4 Uprint("tag对象的全部属性:",tag.attrs)   # 只能得到当前标签的属性(不包含下属标签)
    ; f: G  `3 K* a8 [0 P5 x! e
    + ^. ^8 i' g6 t# `' ]# 获取属性的class的值   根据键取值
    0 ]/ q$ i) Z) d/ Kprint("获取属性的class的值:",tag["class"])0 m, F' C7 k, S) c

    ( b. |+ d9 ^3 b% p% {8 E, [8 s) F2 u+ q0 [2 h: W4 p2 A

    9 e9 K% q6 y; w) e
    ' i8 i# V: ~+ V$ S0 s; E  `( m& Y"""针对获取的标签属性可以进行增删改查"""
    9 P8 ~$ ?& Q$ I/ A# 修改
    * v3 [' w5 K! vtag["class"] = "Logo"& I) G& z% z" T1 t9 B  w- E
    print("tag对象的全部属性:",tag.attrs)( l# \( E% h3 N/ ?: @. t0 L; m: ^
    # 输出属性& `& e0 U' r  ~  W: g
    print("获取属性的class的值:",tag["class"]): t  J. z9 |5 n
    # 新增  属性id  赋值logo
    3 P0 {/ }! H* [2 mtag['id'] = 'logo'. Q8 r/ K8 M; v8 k, e& b/ r
    print("tag对象的全部属性:",tag.attrs)! h. i5 m$ Z5 {% V, n% L0 H# q
    # 删除属性/ f) J. h& w5 w, C! V
    del tag['class']# p* ^% L- y3 W2 P2 P- Q# A
    print("tag对象的全部属性:",tag.attrs)! W# ?8 ~7 P3 z" `) U

    0 i/ X6 t. q, X/ `5 y1 q7 F8 x2 C8 `6 V0 }
    % I+ Q$ M6 M  b
    """针对内容操作  (只针对标签,对属性无效)"""
    , v) k- m/ j- P9 ]# [; y2 E# 获取title标签内容, O& G8 I9 x: E# J2 N. `
    tag = soup.title
    " g. H4 M1 D( N, \2 J$ M# 获取title字符串( q1 \% M& r. h# c: y' U, y
    print("tag对象所包含的字符串:", tag.string)
    ' K9 p- x6 F" sprint("类型:", type(tag.string))
    / A0 X! l  ^3 A. L# 替换内容
    . U; w6 K; t, U& P+ g+ a- gtag.string.replace_with("你好")
    : B, P; N3 a+ T* l; bprint(tag.string)
    6 |# Y* U- \, a# <!-- 学科建设 -->8 g6 Q& D1 y# X( }
    # 获取注释文本内容
    * t/ a; k3 y$ wmarkup = '<b><!-- 学科建设 --></c>'3 F$ x  @! a; p  S7 g3 Z0 U
    soup_comment = BeautifulSoup(markup, 'lxml')) s2 L! L0 X* J. V
    comment = soup_comment.b.string                    # 以markup第一个标签作为关键进行搜索
    , O' N, a! N- |/ A! x* Q( Rprint("获取注释文本内容:", comment)9 f$ h. G9 g. t5 u' A  r4 x# a/ c
    # get_text()9 A/ ?( U! g6 c$ ?
    print("title的全部节点:",soup.find_all("title"))
    9 ?2 e5 X' ?5 c7 D. i3 lprint("title的内容:",soup.title.get_text())- l- w& A" z0 H# X
    """查找ul元素标签"""
    * \; Q3 l; y- z# class是关键名,匹配时后面必须加下划线_
    % r- {- \$ I" c7 D4 e( V3 L# tag = soup.find_all("ul", class_='menu')  # 按照css类名完全匹配
    ! e( t& p& @7 A2 A# print(tag)
    . t+ U- |; n7 w$ N. ]8 Otag = soup.find_all("ul", id='menu')  # 按照css类名完全匹配
    - i9 [; l2 [1 r* y/ qprint(tag)
    : V! Q5 P) q  `, }7 m# 查找名称为a元素的标签内容* l% \; l& u4 u; ^& c% ?
    taga = soup.find_all('a')
    - R- [; T0 W' O0 l7 Xfor tag in taga:( X$ N# w  k) w' L9 D. U$ R
        print("查找名称为a元素的标签内容:", tag.string)
    & Q; m0 x8 M5 ~  r  \# get 获取属性信息  获取整个页面的img标签图片和src属性值
    . [5 M/ t) v; f% `, _, S; stagings = soup.find_all('img')% D2 r; V) b( v
    print(tagings)
    $ p0 v! |7 y0 @+ g# 循环输出图片地址! L/ m  T, n7 K% {
    for imgsrc in tagings:
    ! c4 W2 H8 e8 [& [, n    print(url+imgsrc.get('src'))8 }6 ]) h/ y: Y- m/ }2 i4 K
    9 g# Z! B8 C8 R7 m" R/ W4 Z9 y/ V
    """"属性只能做为参数,所有的操作只能针对标签"""1 p4 Z8 M- f+ g6 C; r6 J
    9 {! m' G3 G5 O5 v
    etree方法:5 W7 I0 s" p- I7 u  c6 {9 h2 M
    导入库文件:% @- u5 z" }3 X& w, z" ~
    ! U# X2 g& ]- h' P) t8 @4 B
    from lxml import etree- _6 z1 m: F! u
    19 J# C2 {3 [6 G8 K$ ~: ^
    解析得到的response对象;3 j, d- s8 ]+ L$ [3 \% U7 g# d

    . z! |. M8 w$ K4 G6 V* a# 设置response的字符集1 C& z! X1 N3 ?" k
    html = req.content.decode('utf-8')' ?: \- _( _# F- ?
    # 解析对象* Z  W/ O7 |2 m5 _
    html = etree.HTML(html,parser=etree.HTMLParser(encoding='utf-8'))
    4 ]3 f5 c2 O( n/ K6 Z1 j* i- x! p0 j
    常用的方法:
    + y1 Q1 k/ B6 P1 M+ h0 h8 e) i1 ]% Y3 h) `/ P& g" b: q
    ) N8 j* r; a1 ]; d+ l
    # 定位head节点(元素)% E% B% q$ a& a+ G! T# q0 e
    result1 = html.xpath('head'): l: M5 a& g8 D: U; ^
    print(result1)
    - e+ P5 G- O( k. Y3 }( @6 x" k( `6 W# 定位title节点& T+ I3 _) L& V* U  V
    result2 = html.xpath('/html/head/title')! S' w: Y. ^$ t7 \' l& e
    print(result2)+ {0 M1 e4 z* Y# q! |
    # 搜索节点  title节点( T3 P3 b$ B  @( `* z
    result3 = html.xpath('//title')
    " R1 Q# ?! Z4 `, m+ w" hprint(result3)
    5 X$ X/ o+ c0 `- l6 m/ a# 搜索title内容  text()得到文本信息6 Y% O5 a( |) M2 u
    result4 = html.xpath("//title/text()")2 R1 x+ ?& A/ j, g. l
    print(result4)
    : e: X- `2 P" s# 搜索div节点
    ' \+ V1 n/ }: S, Hresult5 = html.xpath('//div')1 U. L( C2 @3 F6 N
    print(result5)
    ) {  n& i- [7 [3 ]/ h' x& j9 y# 搜索div节点 并用class属性定位
      h7 o; A8 X0 n) Qresult6 = html.xpath('//div[@class="news"]')
    . B; x5 F: Q. t) R7 g- eprint(result6); N& p2 E7 k! z1 h
    # 搜索div节点 id属性定位$ N5 U1 w6 @. e
    result7 = html.xpath('//div[@id="news"]')
    2 \4 F/ O9 }. B: _print(result7)* }* W; V' N5 \& y2 E" O
    # 获取列表span信息7 B+ y6 r( P/ h& ^7 g4 k
    text = html.xpath('//div[@class="news"]/a/span/text()')
    % y- w  t$ l* ?1 }& G% L$ H  j6 M  Hprint(text)5 y) N5 d/ x2 e: M- Q
    3 |4 L1 d7 B  T/ F: g

    g、通过上一步我们得到自己需要的数据后,下一步就是将我们得到的数据进行保存
    ( j- Z3 y0 ]0 X5 G保存的方式有很多种:2 i" l3 I% J* ?5 ^
    1、保存至文件
    / l1 @" t8 }3 ^6 lcsv、json、text
    9 X) S/ k3 l" ]* Y1 k2、保存至数据库
    . e. m6 y, q# A0 kMySql、MongoDB、Redis 等 (目前主流的为以上列举的三种数据库)

    关于数据存储后面再做详细介绍
    . R5 c- l: O+ J8 F3 C/ Y# J3 A* ]+ @3 a# q* M
    : P3 o6 A' |0 M4 Z6 R5 Q5 j
    ————————————————
    $ z1 T8 e- U6 K6 X  v& K( s版权声明:本文为CSDN博主「royallucky」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    8 c( _& m$ t* I原文链接:https://blog.csdn.net/royallucky/article/details/1059304732 g$ H( b! j" i1 f: u# q0 V

    0 f2 @! t7 o1 \- E7 U* D" J) X6 }2 R4 G5 N& a3 p
    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 05:36 , Processed in 0.615562 second(s), 55 queries .

    回顶部