QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 3694|回复: 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
    * J  h* q# i# w- b. h
    - Z- a: J6 P& M* q# u" I3 c. m

    ( g8 Y9 W& [1 V0 R* c$ V' l( e- J
    手把手带你5分钟搞定爬虫(聚焦爬虫)

      M( m+ X. A/ ?5 s; n8 W, Y4 W% T% x2 g- w: U8 C7 y0 G# ?9 F
    爬虫的原理2 f' F* S# v. k) l2 ?9 ?0 Z- q

    " _# Q4 g8 [2 j对于很多刚入门的小伙伴来说,了解爬虫的工作原理是非常重要的。只有当你了解了它的原理,你才能结合实际情况写出对应的爬虫。下面我将以通俗的语言方式来介绍爬虫; B$ L1 x+ P5 S' `' d6 n
    把互联网比作一张巨大的网,那爬虫就是这张网上面的一只小蜘蛛,在互联网上面有很多的数据,各种各样的数据,我们可以把这些数据比作是被网粘住的小昆虫等。爬虫的作用就是去找到自己喜欢的口味,然后把它带回家,可以储存起来,也可以马上享受美味4 R0 o- o9 u& f" P( O
    所以说爬虫分为三部曲:: F7 j8 Q, A- m0 e4 K+ {! w
    1、明确你自己喜欢什么口味(制定需求,明确你需要的数据类型)
    + l6 L( Y: F8 ~2、去找到你喜欢的食物的位置(得到目标地址)5 O6 Y3 W1 S6 L" v  A
    3、把食物搬回家去(解析网址,获取数据,存储数据)
    : h+ ?+ Y7 c8 r% q3 Z/ a& n, T4 ?它的整个流程就是:(简单的通过request请求获取数据并解析获取数据。以下都是固定化格式,可以照搬)' P/ ~8 W2 m7 {  h
    a、导入需要的库 requests1 o2 ~: @, [% v* Z; I# c* P

    ) f0 L- j  A" V$ r! x6 iimport requests3 a- w/ m. {, C. I( o' [' j, {" G
    10 G7 F6 b$ E; L: ?4 v
    b、明确你要获取数据的网址(这里以百度网站为例)
    8 g! ?8 F4 O0 t7 \2 ]  N  a3 h( u* c1 J/ @+ B% s
    url = 'http://www.baidu.com'  }4 Y6 x/ j9 S) R
    1* V; R6 ~# r; c1 D$ B' `, ?
    c、创建请求
    3 b: r8 \) }+ o
    ! l/ `1 w- @' f) J3 F0 eresponse =  requests.get(url)5 X* `9 W1 _% q: ?0 e2 e8 n/ I
    1% g* v" V" u% Y$ o# x$ u6 l
    d、测试请求是否成功(在实际应用中用的比较少,正常情况都是可以请求成功的,网站对于访问外部信息的爬虫是不会做出限制的)4 ?8 }$ a2 D4 r% }, x2 n" R

    2 P* v2 d7 i& D9 ^print("状态码:",response.status_code)3 s3 m$ E) U& P( A
    1
    4 c: y, t1 b( z当状态码为“200”时表示请求成功;如果不是“200”,很大可能就是你的目标url写错了,核对一下url1 @" m; h4 \6 B! N" g' a
    e、得到网页源码( F6 I- P& {+ d
    1 k' r& I* n4 }/ ]
    print("内容:",response.text)7 P# A1 g9 }5 u
    1; C- X; Z* S; U
    response.content是response.text的二进制形式" O/ n6 O3 {& y1 \
    9 {. \% g6 w6 q+ |/ r# c4 M5 T
    至此,一个简单的爬虫请求就算是完成了。
    3 d( U( Q9 V5 V" M3 o当我们请求目标url并获取到response后,就需要进行下一步:解析网址并获取数据, _& X- U4 D8 H9 ~0 D
    f、解析网址
    1 l8 E. Y7 F* W" o6 @9 i刚开始学习阶段,我们最常用的两种方法,一种是BeautifulSoup,一种是etree。其中BeautifulSoup是最常用的。以下将对两种方法分别进行介绍 (以下方法均为测试用例,实际当中应结合自己的实际情况选择应用)
    ' j8 D6 ~7 t( r3 Z- e. XBeautifulSoup:# ~% D* ?" _" s
    首先导入需要的库文件:4 ]! \: B8 O3 ?
    . C# ^4 M+ \8 V
    from bs4 import BeautifulSoup
    ' M: D$ R" V. P# ?1 a11 B0 I" U9 b9 l/ {# u8 ]( }; f) u: l
    然后对上面请求得到的response进行解析:
    # D- l8 ~4 a( J6 O" M+ Y+ k" U1 X. M" p. C  p3 b4 p; N
    html = respone.content.decode('utf-8')$ V+ o. _+ M* Q% A" H
    soup = BeautifulSoup(html, 'lxml')+ d4 ]7 d7 D6 u8 H* Z. h
    1! [* g7 [+ o6 u& n) g) k: |4 K
    2
    0 t# t0 M1 v" y+ l8 Y) i( r以下是BeautifulSoup中比较常见的方法,有兴趣的朋友可以去一一测试:! O$ `- |+ o5 N1 J5 |3 R3 K
    # 获取head标签- \/ q3 c; m4 @  X2 I
    print('head标签内容', soup.head)3 L4 ~" ^% {+ c+ S9 }
    # 获取title标签  k* a: x  A5 |1 H) P7 R" j
    print('head标签内容', soup.title), ?0 |" s# l% D# Z/ T6 f3 g
    # 获取body里面的img内容  ]3 K; d5 S1 D9 [
    # 通过点号的方式只能获取 下属第一个标签(即获取soup下面第一个body里的第一个a标签的第一个img标签)
    ; m2 T# j  b2 `% \7 J* c2 Y( {print(soup.body.a.img)   2 }! D& p& a" b. C- m/ B& P' T
    # 获取所有的img标签  使用find_all()搜索整个soup对象$ z; x+ Q+ r7 s6 z
    print("获取所有的img标签", soup.find_all('img'))
    / H. x5 X) K2 D# 获取标签中的属性src地址
    " B$ y/ H. q) k; @6 i6 nprint("获取标签中的属性src地址:", soup.img['src'])      # 注意:英文点号都只能获取第一个值: s  A3 m( H+ ?# s: d( O% `
    . g( j3 N) f% p9 p' H, q$ F; t
    ) F7 _+ S6 E; P) V# H. U5 S
    # 获取soup的name7 W# u4 N* F# A( c2 I! D6 y
    print("获取soup的name:",soup.name)
    # o- H8 {' b( K; f: p: {; U# 获取a标签名0 n/ n9 ]. U8 R! V4 C8 l: w
    print("a标签名字:",soup.a.name)- _5 ?( E% u0 h( e/ f3 _
    tag = soup.a
    8 H! {' @8 S$ _print(tag)
    " p2 c  U; ?: S. U# `3 n# 修改操作  a标签改为b标签
    ! ]* a0 D  I* }# s( ^, Utag.name = 'b'   # 赋值后<a> </a>变为<b> </b>1 Y" ^( Z' K8 \: s
    # 输出修改后的内容
    * O  \( a! o  o6 L, G8 m& vprint("输出修改后的内容:",tag)
    " u5 a  Q1 t. h$ j/ k7 Y# 获取全部的属性 attrs$ H3 F: W" W! r2 i* S' S' d7 x
    print("tag对象的全部属性:",tag.attrs)   # 只能得到当前标签的属性(不包含下属标签)0 o: n( M3 ]) Y- |8 a( ~5 ~: X
    ) ^1 i/ Z3 R+ ~6 |" v
    # 获取属性的class的值   根据键取值
    + J& Q) c9 y6 f. E' ]print("获取属性的class的值:",tag["class"])
    2 F1 y' }( L" k9 f1 w$ @+ |3 [9 j1 R) v  w
    9 i" a$ ~& j3 C
    4 Q. ?% F5 X8 l8 u: {7 x
    8 G, Z, N- O2 V
    """针对获取的标签属性可以进行增删改查"""- Z- i8 T) |* b, C( m; h$ e% q
    # 修改/ b& m4 K* e+ W( [, Q* v/ r
    tag["class"] = "Logo"0 `  a4 s' H7 q; R% {6 y, U
    print("tag对象的全部属性:",tag.attrs)
    & T7 w3 X8 m7 P3 x* n# 输出属性) P9 k& T* s" y
    print("获取属性的class的值:",tag["class"])( q, a3 p3 H' ?* _% A* L
    # 新增  属性id  赋值logo; l' C$ q/ A8 ]- v' I' D' y
    tag['id'] = 'logo'
    0 Y. i9 y# k- z4 ?+ d" E& u8 iprint("tag对象的全部属性:",tag.attrs). n! y; [: Q# A- U
    # 删除属性
      D( a" l8 [2 h3 J2 Sdel tag['class']
    9 [5 d# t% T5 v+ S- Dprint("tag对象的全部属性:",tag.attrs)6 ]. ^2 R6 ~4 _" \3 n( B

    5 e$ L9 ^/ j; o% O* n0 F& A* H! S$ t% ~, _4 k1 n' Z+ S

    ( q. k; M+ o. `+ W: Y9 ["""针对内容操作  (只针对标签,对属性无效)"""
    3 e( Y  d( e* q2 {7 g# 获取title标签内容
    7 X4 j  t7 ]5 |$ X" V" F6 x$ K! @tag = soup.title
    - B' |% i6 `6 \# 获取title字符串
    # ?, x  F5 H% f. T6 \print("tag对象所包含的字符串:", tag.string)
    2 Y3 t. O3 h. _# \print("类型:", type(tag.string))
    , i9 @+ I: }7 ?$ [0 f$ g# 替换内容
    ' b' u' F/ z/ ctag.string.replace_with("你好")
    / g( j0 w! g: P2 Jprint(tag.string)
    * V6 F$ r1 ~7 a# <!-- 学科建设 -->8 t$ Q; J6 N/ Q
    # 获取注释文本内容: ~* V; H& t3 X' P6 [
    markup = '<b><!-- 学科建设 --></c>'
    & c  Y. ]5 x, V/ j/ `/ z" d) p; fsoup_comment = BeautifulSoup(markup, 'lxml'): V$ U- Z+ }* d
    comment = soup_comment.b.string                    # 以markup第一个标签作为关键进行搜索  j/ S1 V& c: f9 V. V2 ^
    print("获取注释文本内容:", comment)* v; t+ U- S, I' s, H' X/ O
    # get_text()' j" X4 L* M' u1 t4 v4 [
    print("title的全部节点:",soup.find_all("title"))/ X8 O# K1 Y  U5 `
    print("title的内容:",soup.title.get_text())
    5 r5 I9 I1 N! H"""查找ul元素标签"""- Y8 _; I* J- d  N
    # class是关键名,匹配时后面必须加下划线_) \+ U* v$ }, J# T* f1 q
    # tag = soup.find_all("ul", class_='menu')  # 按照css类名完全匹配
    6 B2 K: I, }0 ~; c2 Q; b# print(tag)$ q  \6 }4 X: a1 w0 W5 t% ]( e: {$ R# n
    tag = soup.find_all("ul", id='menu')  # 按照css类名完全匹配0 t2 U, y3 x: |; v9 M9 b; `( D
    print(tag)2 ~! C4 X: V" ]2 }  r8 F( a, n
    # 查找名称为a元素的标签内容
    , ]' x8 V; G, @* j- d6 ytaga = soup.find_all('a')" l& U# M% c$ B3 [
    for tag in taga:" A" q/ a7 n4 X# y
        print("查找名称为a元素的标签内容:", tag.string)& H/ t! @! I' v/ z
    # get 获取属性信息  获取整个页面的img标签图片和src属性值. c8 v- G& Z) S" T
    tagings = soup.find_all('img'). t) m7 }3 q- u) n
    print(tagings)5 K6 g! n, ^8 I
    # 循环输出图片地址8 F- t: G5 X) u- q: S/ z
    for imgsrc in tagings:" r) X5 ]% j% k$ \0 @' @& R! |
        print(url+imgsrc.get('src'))
    1 p( @. h8 r: I$ K4 i
    , a2 |. r9 Z  c9 m""""属性只能做为参数,所有的操作只能针对标签"""- b- ~8 O/ _0 Z
    ! R5 X( A; ?9 Z2 v4 \
    etree方法:
    5 Q, q0 v8 e/ g导入库文件:
    8 E3 u8 H  W; I/ F# K9 w# N' w# m" ?9 j: _4 [! N% m
    from lxml import etree3 A! r# Y6 f2 I8 Y" e( m
    1
    3 N/ b0 Z( C* w* W7 G9 B' k0 y解析得到的response对象;
    ; H. e, L* N( @$ A% Y& O
    ! M7 e, O6 u. b1 M# P# 设置response的字符集/ M( m! o7 r# C; W7 X4 O
    html = req.content.decode('utf-8')+ u; A/ P0 m/ g; N- F; [0 E9 K
    # 解析对象
    4 v: Z. x- [" d) S1 rhtml = etree.HTML(html,parser=etree.HTMLParser(encoding='utf-8'))& s% |$ l8 M9 q/ `( ?. v
    . s* T! V' ?$ N
    常用的方法:, W3 q9 E+ s) Q, l
    + E, N- ~' _6 b5 `

    2 Y+ h2 k# @+ t1 y& t+ O  @# 定位head节点(元素)
    + N, y( K# d8 R: Iresult1 = html.xpath('head')
    9 D- {) @. w) z" F* t6 J1 l8 Y3 Yprint(result1)% f/ f8 e( F) i* b5 p6 `% G  g3 F
    # 定位title节点: I( T, r, i2 m, u- o$ a# o
    result2 = html.xpath('/html/head/title')
    8 |7 L% ]8 a5 p) C: zprint(result2)
    5 j$ P6 z& ~7 S; [9 G# 搜索节点  title节点
    2 V( `, }+ [7 d7 d- w+ x/ fresult3 = html.xpath('//title')) _, e' h+ b* T  D3 ]1 o+ z
    print(result3)6 {  x7 }- c$ l" O3 b, j4 n; u
    # 搜索title内容  text()得到文本信息
    1 s* l8 w. R+ |% [& j" b8 I2 fresult4 = html.xpath("//title/text()")7 Z& ?: f5 _5 u9 m0 X0 q% `% r/ a
    print(result4)
    ' m1 u' S0 N- r& C! E# 搜索div节点' V) Z/ i' H& V3 [3 M
    result5 = html.xpath('//div')! }5 M/ O  X- H, O
    print(result5)
    . d2 u! A' N3 b" n! M  j- n9 M# 搜索div节点 并用class属性定位" O2 o4 D4 ^2 A% U! s. d, Y, s, Y
    result6 = html.xpath('//div[@class="news"]')) V4 i3 [) r( g/ K
    print(result6)
    5 @0 P3 K1 y/ o! ?( A9 k# 搜索div节点 id属性定位
    * b1 Y5 G2 G* f% b; E# Rresult7 = html.xpath('//div[@id="news"]')
    # }# k/ J/ x: }( ?print(result7)- A9 P$ U4 q/ R( O+ V+ \
    # 获取列表span信息! b, {$ `! A  w6 h
    text = html.xpath('//div[@class="news"]/a/span/text()')
    # N, i1 N, a1 u* g- E  lprint(text)
    * ]2 ]& k- e/ w. q5 d1 L
    7 X8 P( u+ R$ q' c; l2 X! D3 ~

    g、通过上一步我们得到自己需要的数据后,下一步就是将我们得到的数据进行保存
      {. r' M# t. D) _/ y( ^% _! M保存的方式有很多种:
    7 {0 ~3 p" K) R& k4 l  J7 r1、保存至文件
    " v5 ]! ^5 v+ f8 ]6 @+ Qcsv、json、text
    # Y* g1 k+ A: T; y% [6 v+ x2、保存至数据库+ g) I, N, [6 C8 M9 z
    MySql、MongoDB、Redis 等 (目前主流的为以上列举的三种数据库)

    关于数据存储后面再做详细介绍  X8 w+ Z1 m9 p3 r

    7 V5 H" C: b( k% |* ^+ q9 R
    8 G/ b/ R: h! i9 I————————————————
    ! G, z1 s8 \$ [3 c版权声明:本文为CSDN博主「royallucky」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。. Q- D9 H1 W$ h
    原文链接:https://blog.csdn.net/royallucky/article/details/1059304730 c/ D; g8 ^/ e6 s! U6 `0 }0 U
    8 U4 s1 a% O* w

    4 ~/ ?0 r$ _# f" M/ H, r" @% J
    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-13 13:47 , Processed in 0.549677 second(s), 56 queries .

    回顶部