QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 3747|回复: 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+ X, X( `+ R' y' {
    8 F2 a; d- b* P" K0 w" ?" Y

    - E+ r, B5 Z& p  d( T1 N
    手把手带你5分钟搞定爬虫(聚焦爬虫)

    % V+ [% W3 R# E) {/ \0 Y
    ' ?3 z/ j7 k9 c1 L7 E$ ]爬虫的原理4 |3 n& L+ g+ g2 [
    7 p9 P! a  b* r! S
    对于很多刚入门的小伙伴来说,了解爬虫的工作原理是非常重要的。只有当你了解了它的原理,你才能结合实际情况写出对应的爬虫。下面我将以通俗的语言方式来介绍爬虫
    ' ]' C# {& \, q, O把互联网比作一张巨大的网,那爬虫就是这张网上面的一只小蜘蛛,在互联网上面有很多的数据,各种各样的数据,我们可以把这些数据比作是被网粘住的小昆虫等。爬虫的作用就是去找到自己喜欢的口味,然后把它带回家,可以储存起来,也可以马上享受美味
    % j7 M3 b1 {; U8 P) Q! O$ C所以说爬虫分为三部曲:
    1 \* U; Z* D. `( p! _. G3 z8 q1、明确你自己喜欢什么口味(制定需求,明确你需要的数据类型)
    3 R; C/ I9 R7 T* i- Q/ q2、去找到你喜欢的食物的位置(得到目标地址)
    ' a8 W" ~5 [9 n% E3、把食物搬回家去(解析网址,获取数据,存储数据)% L) _( B' X0 |4 {# A$ r. o: k
    它的整个流程就是:(简单的通过request请求获取数据并解析获取数据。以下都是固定化格式,可以照搬)2 ~; x3 @6 B  {% x  ~* w4 ^% [
    a、导入需要的库 requests
    : K% q' ^8 h6 O4 W, Q& M
    . b( }& I( ?1 X( p2 Y5 fimport requests& u8 B- `" K( _0 k- k' i7 E
    14 B9 j9 l4 A7 R1 h. W) s& g) a2 U
    b、明确你要获取数据的网址(这里以百度网站为例)
    ( X3 ]" }  `" h7 F9 Z6 ?. B6 b
    * T3 k1 C; G+ q1 v6 {" q) u( ?* `url = 'http://www.baidu.com'4 y  n# X0 s% t1 k3 u
    1
    ' u$ V7 o) I7 y0 I2 b4 Qc、创建请求& A4 Z" j8 M0 [, q" f4 b
    + q8 z3 u" Y1 |) r6 ]2 a
    response =  requests.get(url)2 Z. h  q0 _8 J! x! |( R
    17 d% F% T& x" }
    d、测试请求是否成功(在实际应用中用的比较少,正常情况都是可以请求成功的,网站对于访问外部信息的爬虫是不会做出限制的)
    2 W4 i6 a; O7 M9 h9 B. {+ I
    ! I( m# T9 l5 g& M( h2 G* G0 Q$ Kprint("状态码:",response.status_code)
    ! l- D0 G# w" D' m. u, l) n1& s$ E' e6 b: Y1 ^6 m# M9 Y) S
    当状态码为“200”时表示请求成功;如果不是“200”,很大可能就是你的目标url写错了,核对一下url) F0 }- O) i5 x  o% o( P% @
    e、得到网页源码
    / u: N' F9 \. f6 S$ m, w. O: g# j2 J% i  R. Y. w) i! E' z
    print("内容:",response.text)% u( w' Z, O. {' A
    1
    3 A3 H2 H! Y% l- K- u) a5 p5 S/ xresponse.content是response.text的二进制形式
    2 t! o! `' M' v7 y2 c
    $ s6 s$ ^4 F! P# [至此,一个简单的爬虫请求就算是完成了。8 _+ m9 [" o" j5 s3 b  ?
    当我们请求目标url并获取到response后,就需要进行下一步:解析网址并获取数据) F  C/ H9 W0 m  C: x
    f、解析网址
    # K* v. o( z3 |& y+ y刚开始学习阶段,我们最常用的两种方法,一种是BeautifulSoup,一种是etree。其中BeautifulSoup是最常用的。以下将对两种方法分别进行介绍 (以下方法均为测试用例,实际当中应结合自己的实际情况选择应用)$ U( Y' |7 j' t: c2 b) ^$ ^( D
    BeautifulSoup:1 b, ^6 T  N& t
    首先导入需要的库文件:% v& Z5 p$ g4 h) Q5 @

    ) W  V5 I# N4 c. dfrom bs4 import BeautifulSoup
    # r( k! K) ~, p+ N, W0 Z& W1
    ) |2 t! I, t5 Y% s+ q然后对上面请求得到的response进行解析:# J5 F; B1 r  {/ i6 l" L5 c# u
    " X8 ^" W. O5 M8 m. F
    html = respone.content.decode('utf-8')
    - k* c* f/ q' Y& L6 Nsoup = BeautifulSoup(html, 'lxml')
    ! \, E0 `1 _! y& _: [2 Q: e  ~1
    8 m/ N# Z/ w0 v1 |2
    4 Z7 d: a- P7 b' ]" A% D以下是BeautifulSoup中比较常见的方法,有兴趣的朋友可以去一一测试:3 C, N& Q  y. J6 ]$ t
    # 获取head标签
    & s- i: a( \( w3 z8 I0 M3 Qprint('head标签内容', soup.head)) U6 E, J" i% u9 u$ p4 ]& l
    # 获取title标签5 y3 }, p6 j: X; @
    print('head标签内容', soup.title)
    7 z! j  M; A5 i  E7 y* r5 @& h; b# 获取body里面的img内容: b# h2 S# S9 t2 Y
    # 通过点号的方式只能获取 下属第一个标签(即获取soup下面第一个body里的第一个a标签的第一个img标签)+ A9 s1 q5 t; d! e+ b4 r; [
    print(soup.body.a.img)   
    , [' ?& k+ c2 ^0 w$ p/ i  O# 获取所有的img标签  使用find_all()搜索整个soup对象
    ! c) O3 k7 u& ?) I1 z# Lprint("获取所有的img标签", soup.find_all('img'))
    ! `0 L; h- w' P3 q1 w# 获取标签中的属性src地址  W( R6 [4 _$ J% F/ N" n1 A9 {6 U1 N
    print("获取标签中的属性src地址:", soup.img['src'])      # 注意:英文点号都只能获取第一个值
    , N' l, Z& S0 G
    2 p4 q% J8 {! \# ~2 ~7 x2 Y8 j: j) n6 ~! h0 b
    # 获取soup的name
    , \% T5 g& |2 kprint("获取soup的name:",soup.name)/ T2 g: y5 J7 r9 W6 v
    # 获取a标签名
      P4 f2 T3 W' D* lprint("a标签名字:",soup.a.name)
    % i* L9 R. Z# q8 etag = soup.a2 J  d0 j" r2 U% J
    print(tag)
    - P! w  j; o! s* I' f2 \# 修改操作  a标签改为b标签
    ( R2 Q# ]6 d# s& _( z' Ytag.name = 'b'   # 赋值后<a> </a>变为<b> </b>- y! ?" O: p- _. M
    # 输出修改后的内容! O# S- u1 T  X: a) _
    print("输出修改后的内容:",tag)
    4 e" d' _( z+ @6 M0 ~# 获取全部的属性 attrs2 b& _" [  i' w, C3 f  R! Q
    print("tag对象的全部属性:",tag.attrs)   # 只能得到当前标签的属性(不包含下属标签)
    + O3 g" w& Q+ h, b" q3 W
    & Y6 ~, i8 B; `# 获取属性的class的值   根据键取值
    . X" g- A6 W( }$ W- ]print("获取属性的class的值:",tag["class"])
    / U/ E1 @% j4 S
    ) y+ b+ f$ N4 D5 i* Z
    7 m* y! N5 s( {  ^6 ~' c% F5 c! T, y7 [  k. p

    2 Y; n8 G( _; ?; D) D"""针对获取的标签属性可以进行增删改查"""6 l9 U. h% V: A1 E6 x; t3 ]
    # 修改
    " H7 M' d! {8 D7 etag["class"] = "Logo"; \  _/ X! o* {! l) U; R
    print("tag对象的全部属性:",tag.attrs); j& m# x' Y5 M
    # 输出属性* i$ e2 P3 c4 x2 T2 F
    print("获取属性的class的值:",tag["class"])
    * @0 W; W9 w# |7 F# 新增  属性id  赋值logo5 |6 ^# b3 |9 {' F
    tag['id'] = 'logo'
    2 f, t" ^  q' x/ l0 U; wprint("tag对象的全部属性:",tag.attrs)
    7 }$ F2 J, Z7 J8 I# 删除属性
    - H3 b3 F2 g+ U! ^- Y% s# E1 G! xdel tag['class']% l3 o& B9 M# B  e
    print("tag对象的全部属性:",tag.attrs)
    9 q& H5 F, T/ n# B5 h8 ?0 O0 c* n, K; E) _" I0 w- I

    ( m. U$ {8 a8 b5 g$ d# s7 v- b
    # [" e" b' H. h. r"""针对内容操作  (只针对标签,对属性无效)"""- s7 t" ]# @6 U! b$ x$ e) I
    # 获取title标签内容
    0 c( ^- c$ B" O$ A$ V7 ftag = soup.title) G: m4 y5 M, i6 Y0 O
    # 获取title字符串
    ' k+ Z+ l7 T. N" F' S6 lprint("tag对象所包含的字符串:", tag.string)
    * j, p( `0 b% \% v0 v% tprint("类型:", type(tag.string))* X! `4 a! b2 d% B) r
    # 替换内容0 g" g+ z& w& o  I: T5 h4 v5 T# \
    tag.string.replace_with("你好")
    $ E( t, I( g9 S5 j8 W- Iprint(tag.string)
    2 ^( p$ |$ W1 J& W' ]# <!-- 学科建设 -->! ~3 a$ d7 r9 B) C+ z( [8 |
    # 获取注释文本内容) J0 U' {! F6 G7 }& C
    markup = '<b><!-- 学科建设 --></c>'
    ' K& m0 ^# p$ Bsoup_comment = BeautifulSoup(markup, 'lxml')1 {2 N0 P: x) [2 v6 G& o! u% o
    comment = soup_comment.b.string                    # 以markup第一个标签作为关键进行搜索% S9 g9 M- C. m$ j7 P
    print("获取注释文本内容:", comment)
    5 i: }- t5 e! g1 q2 v, [# get_text()
    1 d" S7 f. l4 C0 J4 N) Zprint("title的全部节点:",soup.find_all("title"))
    1 |3 q& m& n! i' j! h0 Dprint("title的内容:",soup.title.get_text()), q( x  ?+ A! V% y
    """查找ul元素标签"""
    6 i3 x& h0 U- J: v  f1 g# class是关键名,匹配时后面必须加下划线_
    : V, F8 n7 y. M8 u# tag = soup.find_all("ul", class_='menu')  # 按照css类名完全匹配; X: O, b5 f# H2 ?4 P
    # print(tag)* y$ L4 j0 l! f( |$ K+ v
    tag = soup.find_all("ul", id='menu')  # 按照css类名完全匹配
    ) t9 O7 T; S) p1 l/ Jprint(tag)4 u* ^3 F. Z; X: ^# x6 ^6 F. K2 ~
    # 查找名称为a元素的标签内容9 z! a6 S8 F( p5 O$ t; ~/ _1 Q" S
    taga = soup.find_all('a')) u; U' B4 E. @; S* O! [# g- L
    for tag in taga:
    # {6 r7 M6 Y0 x    print("查找名称为a元素的标签内容:", tag.string)6 y% c8 b% \) x. @5 E( I
    # get 获取属性信息  获取整个页面的img标签图片和src属性值  l2 Q+ a# ~, i; g
    tagings = soup.find_all('img')+ D4 w5 {: J, e
    print(tagings)/ |9 M; p' O( L( Y, S% g- l8 X% v
    # 循环输出图片地址
    ( b5 h" J, w& [1 C' {for imgsrc in tagings:  a( v5 B% D7 X! N
        print(url+imgsrc.get('src'))6 d8 |  X6 Q) w, d& O) S

    , F2 t% _2 ]- Y( p8 o* \""""属性只能做为参数,所有的操作只能针对标签"""& r4 z# g, S2 k* e' @

    $ G( S( p1 F. a7 v6 k0 {  setree方法:
    1 t5 J* @; T/ O8 D导入库文件:3 G9 K3 ~) j! T" F# h% n

    8 a0 l) K2 |. j5 u, x, J' w, |from lxml import etree3 d: G: `% b4 a. ?4 z
    17 Q6 A0 K3 F9 L5 Q" S
    解析得到的response对象;$ r! j6 \5 ^6 e& k) Q1 b
    7 b( K5 l, H% @# P! o
    # 设置response的字符集
    4 L8 F( W; M. `. ~) N: _html = req.content.decode('utf-8')
    # E% R( U+ G7 [7 q$ n$ Q% Q+ W* s& A# 解析对象0 y! A  p5 g4 M: a9 q9 V  d
    html = etree.HTML(html,parser=etree.HTMLParser(encoding='utf-8'))& e4 w5 b+ r& S) Z; D

    " I/ R( [- }$ ~5 R, e常用的方法:
    4 E9 j  ~, c5 \: K( Q$ b4 f
    9 p- F2 e/ l3 X- E& h
    / ^# A2 P& G% i) p) V# 定位head节点(元素)
    0 x. t0 K& q' l( M1 bresult1 = html.xpath('head'). O# X0 p  }9 N+ m( E
    print(result1)& F1 [' d- R# w
    # 定位title节点
    ; @, S2 s& b* J. W9 Rresult2 = html.xpath('/html/head/title')
    % O- ~3 }3 {% b) R6 M9 t; w3 nprint(result2)- N2 K  P% w4 ^) U
    # 搜索节点  title节点
    $ `9 B! W; K! W: x0 t: \; z8 V6 ]! Oresult3 = html.xpath('//title')+ e3 B9 m; g8 U7 G: L3 D
    print(result3)
    3 r9 O5 x- ^7 n9 o. |% `# 搜索title内容  text()得到文本信息& K3 t0 p2 U) V) q
    result4 = html.xpath("//title/text()"): y8 }/ a( S: R* [+ O
    print(result4): U' {/ N; Z4 d; ~
    # 搜索div节点7 D6 A. c4 H: G9 }, Z; s- N0 }, ]/ v
    result5 = html.xpath('//div')
    1 }. W  m, ?9 z3 w6 ?. A& h$ h* Sprint(result5)$ s7 n' \4 J+ F  v  S  f; Q
    # 搜索div节点 并用class属性定位7 G% b3 }% j+ ~0 b
    result6 = html.xpath('//div[@class="news"]')
    3 S- ^) e+ E+ |print(result6)
    ) ^9 I, q- z% d4 p/ O8 l* A- m* B! G# 搜索div节点 id属性定位  h3 y2 \0 m( ~8 R
    result7 = html.xpath('//div[@id="news"]')
    ; f( p: s' F3 R' v; f1 l+ Uprint(result7)
    7 b& z4 v6 v  T4 M1 u. a/ S# 获取列表span信息
    5 `# A' e. z, o  {' M+ otext = html.xpath('//div[@class="news"]/a/span/text()')
    & ]; L  y& l, K5 D1 J4 dprint(text)% V. \" ]) g4 R" J0 M" R- k
    ' l* |( G. A. p% r

    g、通过上一步我们得到自己需要的数据后,下一步就是将我们得到的数据进行保存$ X7 d3 A' M% C  x0 u# O( D
    保存的方式有很多种:
    $ p  q4 @7 U6 u! p4 M) V! d1、保存至文件
    0 S* Y. L" X% |- |$ Jcsv、json、text
    0 p4 d1 G$ `/ t- S2、保存至数据库" _. j/ i2 K9 Q9 d2 A* x
    MySql、MongoDB、Redis 等 (目前主流的为以上列举的三种数据库)

    关于数据存储后面再做详细介绍
    % E( M; y6 N. o' d; z9 r
    - y; b! T/ H1 T! _* Q5 ]; i, ~  z+ \3 ]/ T$ C; X
    ————————————————. ~  N4 y9 K& B( X- D# r
    版权声明:本文为CSDN博主「royallucky」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。' z, r+ i' ]: E; X7 p4 U
    原文链接:https://blog.csdn.net/royallucky/article/details/105930473* z& L( i" I+ V; L& x7 r: d# m( l

    / @( G0 }$ b2 J) ?9 v1 B& a; K  A" R: y: H- E1 C
    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-5 06:15 , Processed in 0.442154 second(s), 56 queries .

    回顶部