QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 3750|回复: 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
    + h$ b- ?  R' r6 O% D
    : T8 c( Y' {6 i( w/ z9 I; U: c

    * i* h5 I+ ~) h, v! \7 u& W
    手把手带你5分钟搞定爬虫(聚焦爬虫)

      x4 m2 v* T! _& u6 i& F
    & j  e: V5 p' f! J! N, q爬虫的原理
    2 `8 i1 p9 @* c+ |+ D" s3 t3 K
    : S7 M( h$ E  }+ a+ J# W, X+ t对于很多刚入门的小伙伴来说,了解爬虫的工作原理是非常重要的。只有当你了解了它的原理,你才能结合实际情况写出对应的爬虫。下面我将以通俗的语言方式来介绍爬虫) i. ?) u  j( z) T" S( P
    把互联网比作一张巨大的网,那爬虫就是这张网上面的一只小蜘蛛,在互联网上面有很多的数据,各种各样的数据,我们可以把这些数据比作是被网粘住的小昆虫等。爬虫的作用就是去找到自己喜欢的口味,然后把它带回家,可以储存起来,也可以马上享受美味2 n( ~; S; V3 k6 A7 W4 i  P
    所以说爬虫分为三部曲:
    + y1 A4 a0 u5 J6 S' r$ \1、明确你自己喜欢什么口味(制定需求,明确你需要的数据类型)
    % o+ G8 V7 N9 s/ A3 ^2、去找到你喜欢的食物的位置(得到目标地址)
    7 |9 E. c0 U# I1 y( w3、把食物搬回家去(解析网址,获取数据,存储数据)! w4 L! ?! T+ ~! M/ H/ W$ A- |
    它的整个流程就是:(简单的通过request请求获取数据并解析获取数据。以下都是固定化格式,可以照搬)0 ^5 W0 P% x2 j. \3 `
    a、导入需要的库 requests
    0 d  I" k) G% c9 ?! a& R  \- s1 y2 ^# w' e- q- `
    import requests
    * f- h# }0 ~1 K( L1 M; k12 ?2 M1 |  m( }7 ^5 ?4 y4 [
    b、明确你要获取数据的网址(这里以百度网站为例)( x* N6 J; V8 f1 c  Q
    # v; P9 d- t4 M( P
    url = 'http://www.baidu.com'+ ~3 x3 c( W9 _1 {: I  j- n
    1
    : v: P! h; t. Q2 z1 ?2 yc、创建请求! w/ w5 [4 u' h  }$ o9 @7 h
    3 k5 e; w! V" P& q+ j9 q
    response =  requests.get(url)' i; P) b) ]& P( r7 D4 _' Y6 p( A
    1
    1 l2 b- p, b0 o) o% D+ H5 Fd、测试请求是否成功(在实际应用中用的比较少,正常情况都是可以请求成功的,网站对于访问外部信息的爬虫是不会做出限制的)
    / J, Y1 i  [: ]+ i  B% t$ U2 b6 [) x7 A) C: z
    print("状态码:",response.status_code)  u/ `2 i: Y, x' _7 J6 K4 O2 t2 t
    1$ T* j! G) a/ D9 C3 M
    当状态码为“200”时表示请求成功;如果不是“200”,很大可能就是你的目标url写错了,核对一下url
    ; Q4 {  a; M( e! K+ _3 n) e# Y4 \e、得到网页源码. S$ F  M! D7 V: o( J

    ( M' M( A/ Y6 S$ i- Gprint("内容:",response.text)
    ; I! ~! V; @  {" @7 ~1
    7 W$ z/ N9 {% n* M. vresponse.content是response.text的二进制形式
    . h2 l3 X: `) b8 Q5 T% Z* [, R9 `, f1 k
    至此,一个简单的爬虫请求就算是完成了。$ U  B- J, v; ?( Y8 n
    当我们请求目标url并获取到response后,就需要进行下一步:解析网址并获取数据
    & ^+ Y7 `/ T5 b8 z$ J5 |f、解析网址* [1 Q3 J. r; t, y* y: m4 d
    刚开始学习阶段,我们最常用的两种方法,一种是BeautifulSoup,一种是etree。其中BeautifulSoup是最常用的。以下将对两种方法分别进行介绍 (以下方法均为测试用例,实际当中应结合自己的实际情况选择应用)
    9 L3 E9 x7 C* D- S2 MBeautifulSoup:
    # i  l5 E' z' ~0 m& }* w% e1 W1 ?首先导入需要的库文件:
    ; `4 {8 L2 C/ F- ]2 ~  d& a$ Y5 i# C8 C  `9 m
    from bs4 import BeautifulSoup! @& ?% x2 E" N/ o
    1
    2 V& J- s. ]5 S& _然后对上面请求得到的response进行解析:
    + Z( R1 ]4 U, \
    ! Y6 i$ x* D1 r- q7 c  W; B* Xhtml = respone.content.decode('utf-8'). z$ \5 P8 I" X5 b, D
    soup = BeautifulSoup(html, 'lxml')
    & e3 m, V4 ]$ P6 T9 X6 T/ Y17 u8 c: w0 h% D& e
    23 ]+ P" s4 c- k. n. J. G
    以下是BeautifulSoup中比较常见的方法,有兴趣的朋友可以去一一测试:& s$ U. \7 {5 T' [% Q! s2 |! J( |
    # 获取head标签
    : ?, O5 v. ]7 h- I. {& l& Cprint('head标签内容', soup.head)9 _6 g: j9 e# Q
    # 获取title标签1 \; a! n, T# Y
    print('head标签内容', soup.title)
    4 |+ _3 |" w3 p  L$ ~# 获取body里面的img内容( v  q" Q4 e& U* v+ ~- Y
    # 通过点号的方式只能获取 下属第一个标签(即获取soup下面第一个body里的第一个a标签的第一个img标签), Z9 d! k. @! _, m1 t
    print(soup.body.a.img)   
    ) @2 q" G1 `; M# 获取所有的img标签  使用find_all()搜索整个soup对象, h/ s2 q3 q4 o
    print("获取所有的img标签", soup.find_all('img')), ]! h0 B" p5 q$ ?$ m& j* O
    # 获取标签中的属性src地址
    : N) z3 U1 X: @4 Wprint("获取标签中的属性src地址:", soup.img['src'])      # 注意:英文点号都只能获取第一个值2 b3 H) e2 n; D& M: T4 `  n
    . o2 j/ o0 s& |' j( ^! u0 k

    - h- m' U1 Z; L8 h) T# 获取soup的name7 I' f3 [1 Z8 p$ H4 [% b. n
    print("获取soup的name:",soup.name)" j  y- Q! X" q" N
    # 获取a标签名
    5 A4 ]/ ~6 ]3 @# H5 ^& P3 Fprint("a标签名字:",soup.a.name)
    " V* l. ]" s3 ?& P3 {6 l% ctag = soup.a1 j# ~( p; a# y: k
    print(tag)
    ( h% U; [  w+ ]4 |& ]# 修改操作  a标签改为b标签
    ) J2 m; O& |# dtag.name = 'b'   # 赋值后<a> </a>变为<b> </b># \/ z: [; O: Q; C& V
    # 输出修改后的内容
    ! \7 c# {4 K; N/ L: gprint("输出修改后的内容:",tag)  z5 u( Y% r; {! H- |) o
    # 获取全部的属性 attrs! _8 a0 H& m( k% Z5 N
    print("tag对象的全部属性:",tag.attrs)   # 只能得到当前标签的属性(不包含下属标签)
    / z. Z% H: r* X# R0 D9 v! R" a; _. |/ A  U" i
    # 获取属性的class的值   根据键取值
    ! d1 I/ `5 @% k/ i/ sprint("获取属性的class的值:",tag["class"])# M0 h1 u/ s- y9 Z9 L3 a, [) O

    * G5 w3 O8 `' [. W9 @& P
    % o2 L# Y+ o3 `' g4 a  F- r) B. I% e7 m  X0 ~( m

    7 s) y6 `. u: y! R"""针对获取的标签属性可以进行增删改查"""
    & |! ^& Z5 }6 O, }  _' j# 修改
    % \/ ]  {+ U; P4 u& utag["class"] = "Logo"
    3 A: c. Q" P5 Qprint("tag对象的全部属性:",tag.attrs)
    8 k. d5 e& o4 P3 y& i# 输出属性
      j; h6 G  A9 K4 i/ R8 d( tprint("获取属性的class的值:",tag["class"])- ~$ m) b7 z# D+ h
    # 新增  属性id  赋值logo$ i" K5 j  l: d/ W" r: P) A4 M
    tag['id'] = 'logo'6 f, Z6 q/ Q8 ?) G$ o
    print("tag对象的全部属性:",tag.attrs)
    0 [# F  j6 t/ _) ~8 S; u# 删除属性7 m  P2 c3 I. O+ }2 t$ f8 `; ~
    del tag['class']
    * Z, n$ q/ @* |* J: tprint("tag对象的全部属性:",tag.attrs)* m7 r: l, F" n0 p* e  Z( y
    4 q( `: P& x; k! ?
    % F1 q1 W& q0 h. _- B4 }# f# k( x
    - W! @4 h" r2 y! n. b- i7 V) C
    """针对内容操作  (只针对标签,对属性无效)"""
    * f; y* |" ^& X2 |# 获取title标签内容
    8 m0 l5 f, W- {tag = soup.title
    * n5 T2 ?/ B0 q1 Z5 B# 获取title字符串
    - `& ?/ t+ @! G# t1 hprint("tag对象所包含的字符串:", tag.string)
      {3 A' l- _% T  }; U* Y4 b* W# e% Yprint("类型:", type(tag.string))
    5 A% T" j: {! _# i# 替换内容
    6 P" ?1 c) Z# Z, ], }3 n$ Btag.string.replace_with("你好")
    / j* x: q6 `6 b! `8 @! }: Bprint(tag.string)
    $ W6 Q& k; j0 w; ?; n# <!-- 学科建设 -->
    " t* }9 g9 K2 z( I- \; |9 F# 获取注释文本内容+ M# K* [( U' N6 a5 x' d
    markup = '<b><!-- 学科建设 --></c>'
    6 j* W) m6 P. D) Wsoup_comment = BeautifulSoup(markup, 'lxml'). |/ o9 P% _3 D/ F3 t
    comment = soup_comment.b.string                    # 以markup第一个标签作为关键进行搜索
    ) X% ~/ D/ y- A) d* U  n1 \print("获取注释文本内容:", comment)
    5 p: b" B( V1 T% G# get_text()
    * j2 P0 L. u- Y5 l% H5 gprint("title的全部节点:",soup.find_all("title"))7 L1 }1 o0 b5 Q2 W
    print("title的内容:",soup.title.get_text())- p( i1 r4 `4 l3 v7 \  C' h
    """查找ul元素标签"""9 _2 q- q, G. A, ]1 U& R# `! J' C
    # class是关键名,匹配时后面必须加下划线_! l0 s0 O8 X; J
    # tag = soup.find_all("ul", class_='menu')  # 按照css类名完全匹配
    8 k& \9 W4 D( U* u# print(tag)* X  w  h8 y$ w/ a, d" Z
    tag = soup.find_all("ul", id='menu')  # 按照css类名完全匹配
    ! k+ s/ R; B+ e; fprint(tag)8 \; W$ P7 j# A
    # 查找名称为a元素的标签内容
    5 X- ?& _; y- h( e4 ztaga = soup.find_all('a')9 k5 n  W9 ^/ `5 h, m* S0 j4 |, |
    for tag in taga:
    ( o5 j  ^2 e3 i' i. p8 d3 v' ~    print("查找名称为a元素的标签内容:", tag.string)
    . C! h/ `& o% [/ C$ l# get 获取属性信息  获取整个页面的img标签图片和src属性值
    : `  M7 L; V, t" \tagings = soup.find_all('img')
    * n  k% [6 C% G0 A3 e; cprint(tagings)5 L  h6 w( J( e9 i
    # 循环输出图片地址
    6 g, ~+ a! W  ?6 Y6 R1 z0 o3 G+ ifor imgsrc in tagings:2 l+ F- L# U) W6 ?' o
        print(url+imgsrc.get('src'))* o8 ^& o$ {$ f

    3 E3 I9 W7 J/ \7 o! T3 R0 u' q2 Y""""属性只能做为参数,所有的操作只能针对标签"""9 B& K- y- P  A! s" |
    . g4 I$ E) k- Z/ o2 o
    etree方法:- C! |& X4 n6 Y9 [& U8 o2 T' V
    导入库文件:2 P$ y! H' k6 [6 B$ w  Z( ^. C' L

    3 n! d: i' [* O* v5 c. [7 Hfrom lxml import etree
    - a( g! \+ T: }: }" P1
    * O- u9 Q! _5 S, v& ?6 h解析得到的response对象;# v5 Q0 x- G' h

    6 G' P: l/ R1 D# 设置response的字符集
    / @3 E( s: ?/ D/ E) i" C: s* Lhtml = req.content.decode('utf-8')  z3 u, o  {7 i6 H* h# t% u2 X# n7 p
    # 解析对象
    . m8 y$ A/ x$ l" L) }2 ~html = etree.HTML(html,parser=etree.HTMLParser(encoding='utf-8')): S9 Y8 b0 v6 u9 d
    ; }% v9 c0 g9 u- \
    常用的方法:* X1 B4 x' |6 s0 R3 l3 p1 Y4 k
    1 a- ^. k1 l3 L

    % ?4 {% x* _$ Y; s# 定位head节点(元素)
    ' x$ v& e( b- W4 j" u; zresult1 = html.xpath('head')+ @; l* x$ d3 S3 a/ }  f
    print(result1)
    " }- T  _$ Q. u* t! v. ]+ r# 定位title节点
    2 l1 c" v$ _: Y* G! {8 Uresult2 = html.xpath('/html/head/title')
    4 ?0 j' e/ U( aprint(result2)& V/ I# a( @6 K, z" ~$ q* W0 ]
    # 搜索节点  title节点" t+ b7 A" Z4 s: H' t2 x
    result3 = html.xpath('//title')
    ; V& N# r& f: T& k1 g4 m- n6 cprint(result3)3 M" G) `$ P3 |+ U' E+ {7 g
    # 搜索title内容  text()得到文本信息
    " H& h, g3 Q. b, J, d# f8 g/ Wresult4 = html.xpath("//title/text()")% g% _) E- j" k) [
    print(result4)# Q9 n9 z! F; F: [! X2 v
    # 搜索div节点' e( F$ K3 X; z  k$ P# f; w
    result5 = html.xpath('//div')1 a( t$ e) V7 I3 [
    print(result5)
    ' T7 n" i# J) }* ^# 搜索div节点 并用class属性定位3 O( o5 M5 i9 t6 t, o; R
    result6 = html.xpath('//div[@class="news"]')
    % G# {4 e% S0 r  tprint(result6)
    ) H, L+ x" w  w  E5 N8 H( S, F% J# 搜索div节点 id属性定位3 @8 k! @3 b. d+ t
    result7 = html.xpath('//div[@id="news"]')
    4 y1 E) D- b/ H# uprint(result7)
    4 {1 h5 Z( b$ w# 获取列表span信息
    , d1 X) K8 A7 gtext = html.xpath('//div[@class="news"]/a/span/text()')
    - x9 a' r' o3 Rprint(text)
    6 v/ m1 O  B# R
    ( t6 B8 I2 P3 X- x1 d

    g、通过上一步我们得到自己需要的数据后,下一步就是将我们得到的数据进行保存0 ~0 E& {; G; L9 |
    保存的方式有很多种:: R6 o" u+ Z. k! x( x
    1、保存至文件5 Q9 K; \: z) `5 E# L) H" z, y4 P
    csv、json、text, h% v( ?3 U5 y6 N* n3 B
    2、保存至数据库
      |: Z" U  u& Z# s( \MySql、MongoDB、Redis 等 (目前主流的为以上列举的三种数据库)

    关于数据存储后面再做详细介绍3 T, {8 l3 i7 S, I2 U8 B

    ( n) W6 M( D6 d
    # m' W4 r: d- j  W; ]' U8 |————————————————5 Q- ]7 M# p7 Y1 y
    版权声明:本文为CSDN博主「royallucky」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。! a7 F' A7 G9 E; ^3 l  W
    原文链接:https://blog.csdn.net/royallucky/article/details/105930473) {1 p$ g  A+ _3 J) e

    6 I. l( X! Y4 R+ B6 E& e: c8 r$ n# C$ \  Q3 Y
    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-8-6 03:59 , Processed in 0.429500 second(s), 56 queries .

    回顶部