QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 3696|回复: 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
    " B- b+ ?9 E2 j
    ' B$ v+ Z# r; o! x/ H: m
    7 F% E3 A: A' W# n( {4 M8 C/ A
    手把手带你5分钟搞定爬虫(聚焦爬虫)

    , q, Y) O/ @/ Y8 E# I4 \% K3 Q' {, X6 b; Y' J3 ]0 J! X, p
    爬虫的原理; v! q8 a7 a( Q, W! a, n; S/ a

    % i! y2 p  Z+ H9 V' ?对于很多刚入门的小伙伴来说,了解爬虫的工作原理是非常重要的。只有当你了解了它的原理,你才能结合实际情况写出对应的爬虫。下面我将以通俗的语言方式来介绍爬虫+ [. T1 T) V4 A% T4 U
    把互联网比作一张巨大的网,那爬虫就是这张网上面的一只小蜘蛛,在互联网上面有很多的数据,各种各样的数据,我们可以把这些数据比作是被网粘住的小昆虫等。爬虫的作用就是去找到自己喜欢的口味,然后把它带回家,可以储存起来,也可以马上享受美味( @0 H2 K( ^' m$ k, R! j6 Q6 ~5 B' s
    所以说爬虫分为三部曲:+ K0 _  v9 Y, {/ Q& L5 {, e! c9 ~3 l
    1、明确你自己喜欢什么口味(制定需求,明确你需要的数据类型)
    % t# k: C4 z3 b) g4 Z2、去找到你喜欢的食物的位置(得到目标地址)
    7 ?8 ]" _& ^5 B' F) p' E3、把食物搬回家去(解析网址,获取数据,存储数据)
    ; s; T( ]" D% x它的整个流程就是:(简单的通过request请求获取数据并解析获取数据。以下都是固定化格式,可以照搬)
    + ]% h6 C5 F1 C5 wa、导入需要的库 requests7 y; Y/ n5 ?# z0 t+ z, }, }
    8 I& O5 Y  y  p& E' N
    import requests
    6 _8 L  B+ a$ i. J" K# @# B- I1  R* S: p2 U- T: r9 M
    b、明确你要获取数据的网址(这里以百度网站为例)
    + g% e: s  s" z8 @
      n& M, b7 ]% e( ^4 j9 Y9 Iurl = 'http://www.baidu.com'1 U" F9 k' Y  L: T! y# N# B* l9 I
    1( k0 z0 k  N. Y) z6 `
    c、创建请求
    + v  j. A- ^; H. r2 }, M& o5 F  a7 ]% x/ f6 L1 h$ D: H8 R9 h
    response =  requests.get(url)
    / L$ f0 f: I+ p+ s16 v0 P% L8 u' L4 v
    d、测试请求是否成功(在实际应用中用的比较少,正常情况都是可以请求成功的,网站对于访问外部信息的爬虫是不会做出限制的)* s+ m" L7 P( k4 @

    $ l) X0 ~! Q9 }) V& bprint("状态码:",response.status_code)
    2 w* K$ Y- A! t) M+ A4 S0 B1- v" @9 m, a4 I6 y
    当状态码为“200”时表示请求成功;如果不是“200”,很大可能就是你的目标url写错了,核对一下url5 O! Z4 D. V9 r8 L8 i+ x+ T& `
    e、得到网页源码
    6 t& ~* N5 u( u, ?  H, N1 P0 M
    / N, _; X. d# R& Q# U6 S) Mprint("内容:",response.text)0 f( i# m% K; x7 t" i
    1( c& {$ o" I; d( P3 U; Z, l
    response.content是response.text的二进制形式' i. z1 R! t: `& @' B1 |; O
      q1 u2 U, G- Z$ S. \
    至此,一个简单的爬虫请求就算是完成了。+ c  n: V: t2 L
    当我们请求目标url并获取到response后,就需要进行下一步:解析网址并获取数据
    2 X& f) i8 [7 O+ Y) z) [f、解析网址, x4 i# X& a2 \( p+ B& G, B
    刚开始学习阶段,我们最常用的两种方法,一种是BeautifulSoup,一种是etree。其中BeautifulSoup是最常用的。以下将对两种方法分别进行介绍 (以下方法均为测试用例,实际当中应结合自己的实际情况选择应用)
    ) N" N# c7 C# vBeautifulSoup:
    : B; [. x) B: K首先导入需要的库文件:2 c0 i; m3 B. F, \6 a- P9 S
    3 a/ p1 v; N( L$ m% J5 {
    from bs4 import BeautifulSoup
    ' S# o* H$ p" G/ c& D/ P9 H1
    7 J$ c- J. ^* v* R; o0 K( g% C) Q然后对上面请求得到的response进行解析:
    $ h5 s2 `' V+ O
    , V0 p  a7 O" ~. ahtml = respone.content.decode('utf-8')- F5 r6 U! \" E4 Y
    soup = BeautifulSoup(html, 'lxml')1 k) Z7 l7 r. v- o
    1
    2 P) x* e( y6 ^2% y& N* F# R8 E) G' X9 f
    以下是BeautifulSoup中比较常见的方法,有兴趣的朋友可以去一一测试:
    % p4 @& i% o) N! ~) q9 K# 获取head标签, H, B0 t' }' ]& f
    print('head标签内容', soup.head)# k  E1 V" [1 c
    # 获取title标签
    . E9 s) L, P7 j% \1 Uprint('head标签内容', soup.title)2 ^$ W) A$ K8 t& k0 D  e) P. \
    # 获取body里面的img内容" ^( y4 n$ s5 f: o$ N/ O; `
    # 通过点号的方式只能获取 下属第一个标签(即获取soup下面第一个body里的第一个a标签的第一个img标签)
    / I+ e( l9 `* c  _print(soup.body.a.img)   0 [# V+ K( ?1 O# _0 D) i( `. o
    # 获取所有的img标签  使用find_all()搜索整个soup对象
    + ~) H1 C) I9 {  N* aprint("获取所有的img标签", soup.find_all('img'))$ @3 u( c0 N! d  L& g
    # 获取标签中的属性src地址" Z9 k+ G0 C( _1 b( y& f# B! x
    print("获取标签中的属性src地址:", soup.img['src'])      # 注意:英文点号都只能获取第一个值# n& X( Y  k0 r1 T  M% b- T

    8 z! @( H7 m( @, I- H
    # p4 W! _4 n4 p# 获取soup的name- |! \& s, @; b1 M
    print("获取soup的name:",soup.name). A. O, ]% R! p; g
    # 获取a标签名2 r5 s; ~. O- j& R  Y$ c, P7 F( j
    print("a标签名字:",soup.a.name)
    1 y# M+ C. \8 Q, J3 M  V8 etag = soup.a  v- W2 ?) g1 g5 [3 ^0 y
    print(tag)% L: N) Y5 T" P- R2 |
    # 修改操作  a标签改为b标签+ \2 A4 L1 _. V+ A8 [0 f; u
    tag.name = 'b'   # 赋值后<a> </a>变为<b> </b>
    1 e3 ^: `& ?0 J( h  ^# 输出修改后的内容/ m/ v' l) {# R3 L
    print("输出修改后的内容:",tag)9 b  ]( r9 D. d" D' e  [# K! \4 d
    # 获取全部的属性 attrs
    7 D- W9 x# F; tprint("tag对象的全部属性:",tag.attrs)   # 只能得到当前标签的属性(不包含下属标签)! j0 X* ?4 ?/ M  Q* z+ N
    " t- Z3 ]+ R2 {& A7 i: W1 H# _
    # 获取属性的class的值   根据键取值% P- v+ s9 _; x7 `
    print("获取属性的class的值:",tag["class"])
    * Y, z4 o8 v, @0 U3 n' X2 c. F% T9 |* t7 ?& j

    1 Z5 A0 n/ g, |+ |! W7 d8 y, r
    5 o' b: A7 s9 R' B4 `
    # f. s6 U" ~$ L9 D' {"""针对获取的标签属性可以进行增删改查"""
    4 D1 l$ Z) w" h+ C# 修改) D7 p  I: W: y2 q: n9 m$ b, t" n2 {
    tag["class"] = "Logo"
    0 y- W  Q% I4 fprint("tag对象的全部属性:",tag.attrs)
    , x/ V' |2 x) }2 O5 P& g$ e# 输出属性
    7 S1 z, `2 p8 Q5 l9 [$ v! vprint("获取属性的class的值:",tag["class"])4 J9 z' R+ s' W9 i8 ]
    # 新增  属性id  赋值logo7 w2 S3 @- p0 _
    tag['id'] = 'logo'
    + x' `; a# L  S$ M) rprint("tag对象的全部属性:",tag.attrs); L* ^$ ]: Z8 l+ w$ X  W, ^
    # 删除属性
      F8 S  Q) r& G" x1 G2 E6 b9 ^del tag['class']
    ; G8 G1 l3 L( |( a6 A* Yprint("tag对象的全部属性:",tag.attrs)3 u: N4 @2 C; M# `

    / w9 Y7 @; v9 W$ i. r3 i  H% d( R( W5 u8 q8 I0 a$ c/ F

    2 ]0 d, P# e; D. X9 _) W"""针对内容操作  (只针对标签,对属性无效)"""7 p( Y0 e. w* P/ n; B# B
    # 获取title标签内容% U6 c% m" r1 E, W1 i4 \
    tag = soup.title
    3 b0 V; S( T" C* T" V, x, V# 获取title字符串0 i/ n  y( [* }4 C# D- s+ V0 ^
    print("tag对象所包含的字符串:", tag.string)
    " v) }( d/ o2 b/ U0 bprint("类型:", type(tag.string))
    7 f( h" U8 m0 {6 ?# 替换内容# c0 ]8 D& D  S2 Q# E9 d7 |$ {
    tag.string.replace_with("你好")$ I$ [) D$ J3 e0 c0 d' v- @
    print(tag.string)% K% i. m& R% y4 V
    # <!-- 学科建设 -->
    : }. O  i3 Y* z* {# 获取注释文本内容
    ( w( M3 W3 W7 T& g. J5 s& }. [markup = '<b><!-- 学科建设 --></c>'
    0 \/ I! [/ |) v" J' ]" `soup_comment = BeautifulSoup(markup, 'lxml')' e! F! O2 w" ^
    comment = soup_comment.b.string                    # 以markup第一个标签作为关键进行搜索  ~) n" A- X) l1 G- h
    print("获取注释文本内容:", comment)+ }; \( @) P6 R* w/ @
    # get_text()
    0 U7 K1 `+ ^, M. q* jprint("title的全部节点:",soup.find_all("title"))5 R0 I3 H+ c0 v! {
    print("title的内容:",soup.title.get_text())
    . b  l6 `# K4 q; H"""查找ul元素标签"""
      |" |; ^7 T+ }, F# class是关键名,匹配时后面必须加下划线_8 I% P9 n$ M$ i2 \
    # tag = soup.find_all("ul", class_='menu')  # 按照css类名完全匹配
    * t# n# T* h5 k; w. C4 H" \# print(tag)
    9 e, U% N1 M6 G7 }0 A0 Ltag = soup.find_all("ul", id='menu')  # 按照css类名完全匹配3 T( e0 i4 s$ X7 y! p. y' ~! g
    print(tag)
    & p# P" x" V: _# 查找名称为a元素的标签内容
    ) v/ o$ P/ z$ ^' U3 M0 Htaga = soup.find_all('a')
    7 s2 p" u. v" C# afor tag in taga:
    5 m) B5 a# b8 P    print("查找名称为a元素的标签内容:", tag.string)
    5 `0 p# V/ g( H4 \# get 获取属性信息  获取整个页面的img标签图片和src属性值
    & P" @( N+ \0 w+ B5 [' h. t& t: Ltagings = soup.find_all('img')
    ; I! P" @  K) g! Pprint(tagings)4 g# {' k; N8 N' O% r$ k
    # 循环输出图片地址
    9 M  h8 w6 S1 j# J" vfor imgsrc in tagings:
    6 |- [2 E& ?; e. j    print(url+imgsrc.get('src'))
    , |* n. q; Y, e' L- _- `, G# }* [8 t
    """"属性只能做为参数,所有的操作只能针对标签"""  c; g, M6 |: d. {; p& w. i
    8 L# E1 d2 N' @( R7 ?
    etree方法:
    - j3 \6 w  l5 y  Z9 W+ [) E6 p导入库文件:
    % F* r& S3 }2 t; M) }* b& c( V( w- P4 R
    from lxml import etree: E" Q9 O3 S# B1 D0 S
    1
    6 u% t1 h& O4 B" }( i4 U7 d解析得到的response对象;
    % \% o4 o7 V8 d. R$ Y
    : A/ y  F9 ]8 h3 w; j+ i. c# 设置response的字符集
    " n: K( x1 P- Q$ T2 ]; F5 ~html = req.content.decode('utf-8'): o7 L) z6 x$ ~  j; N
    # 解析对象- P7 \$ I7 v6 a  t! V7 J4 }
    html = etree.HTML(html,parser=etree.HTMLParser(encoding='utf-8'))% G6 y/ U1 Y3 U  O. E% K

    3 h( m) [! V" |4 X0 I- S常用的方法:/ n* L0 p# D) I5 V0 p
    ) Z' q1 W: g( y, K6 ~9 c
    4 }  U/ {  a9 G8 Z" g/ j. ]) [
    # 定位head节点(元素)
    . P: [. j- ?: A) B, U) n' z: presult1 = html.xpath('head')
    + L$ B5 U) d: a+ V6 tprint(result1)
    ! i5 K$ G; |9 _- X7 Q8 k- V2 t# 定位title节点
    7 b! `" ^0 F9 D4 H7 r; R. cresult2 = html.xpath('/html/head/title')
    + @* w( f( z7 L+ t5 Qprint(result2)
    - |: g5 }0 v" R( t+ q' E# 搜索节点  title节点, L! ?+ F8 @- D6 w1 _
    result3 = html.xpath('//title')
    ' s3 C2 M+ Y3 n8 A% Z' l  Mprint(result3)
    ; h! y2 F& a7 H- b4 ]. h1 {# 搜索title内容  text()得到文本信息! N' w( v3 z% i" Z
    result4 = html.xpath("//title/text()"), L# U3 j' a7 z. ~* L7 ^
    print(result4)
    & ^0 v6 v/ s9 h6 p  P# 搜索div节点
    & {) Q6 Z9 m1 r  ]) L* c# Mresult5 = html.xpath('//div')) f- z) U! e0 A8 q
    print(result5)$ ?2 a% x9 y( y
    # 搜索div节点 并用class属性定位( _! [( c7 M: [  G
    result6 = html.xpath('//div[@class="news"]')1 `- L& O. z; O5 C& R) E) P
    print(result6): N( x$ M5 G. Y2 y& J' a) O
    # 搜索div节点 id属性定位' g3 f4 y, K/ K2 b; S- g
    result7 = html.xpath('//div[@id="news"]')
    , b: |% H- ?5 T- jprint(result7), n- K" ]. {9 k6 u( l) O
    # 获取列表span信息6 H" ]2 n: e  P* |) B
    text = html.xpath('//div[@class="news"]/a/span/text()')
    * e6 V/ r" R6 G. y, nprint(text)
    ; m* a( Z6 g6 J) o3 D& f
    6 ]) _, D5 F& `

    g、通过上一步我们得到自己需要的数据后,下一步就是将我们得到的数据进行保存
    6 s$ S6 G- n2 a% U% i8 w保存的方式有很多种:
    6 E( s0 m) ]% C# n8 j7 P" l/ E1、保存至文件
      [/ E2 x7 y6 W& y7 T& Zcsv、json、text- n/ O# T7 `0 f" ?  q$ R+ l* l0 l
    2、保存至数据库
    # V+ z5 E* v# H2 p! o! w  ~$ g; dMySql、MongoDB、Redis 等 (目前主流的为以上列举的三种数据库)

    关于数据存储后面再做详细介绍
    5 E* X  Z$ S" Y8 O3 Z
    ' |' d" o, \" V
    6 t8 i  \  U% N7 H6 L1 S————————————————& d9 I% ]2 l3 D0 R! }
    版权声明:本文为CSDN博主「royallucky」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。7 N9 z/ u" w/ r9 t  m5 J
    原文链接:https://blog.csdn.net/royallucky/article/details/105930473
    ! B+ n4 p, T7 |3 O% I4 t1 Y$ i+ R, c; ]

    ; Y( u" l8 ]; A5 y8 \: G& 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 01:55 , Processed in 0.444537 second(s), 57 queries .

    回顶部