数学建模社区-数学中国

标题: 手把手带你5分钟搞定爬虫(聚焦爬虫) [打印本页]

作者: 杨利霞    时间: 2020-5-5 14:21
标题: 手把手带你5分钟搞定爬虫(聚焦爬虫)
7 |* e- w% m' U% a; @! }" L/ D  @

. P5 z0 _# C. i, B- }8 p

$ O: d+ b! M3 x5 g  [: N
手把手带你5分钟搞定爬虫(聚焦爬虫)
; w6 e1 u4 }4 F, T. X* u8 d
* F, C2 B. v& ~1 g+ t/ k9 {$ y$ X
爬虫的原理( v) M+ p- g7 T! S) }9 T
7 w1 i; |" r% |7 a& i0 {
对于很多刚入门的小伙伴来说,了解爬虫的工作原理是非常重要的。只有当你了解了它的原理,你才能结合实际情况写出对应的爬虫。下面我将以通俗的语言方式来介绍爬虫, G- Q6 F- P, W( o8 o9 L, ]( C
把互联网比作一张巨大的网,那爬虫就是这张网上面的一只小蜘蛛,在互联网上面有很多的数据,各种各样的数据,我们可以把这些数据比作是被网粘住的小昆虫等。爬虫的作用就是去找到自己喜欢的口味,然后把它带回家,可以储存起来,也可以马上享受美味) D; L" V1 A. m$ ~
所以说爬虫分为三部曲:1 ~+ d0 P5 x0 H0 S# `
1、明确你自己喜欢什么口味(制定需求,明确你需要的数据类型)
; D* V+ T3 l4 D4 k9 ?2、去找到你喜欢的食物的位置(得到目标地址)
" Y, d7 F2 ]8 y. e: L0 |! H6 |9 @3、把食物搬回家去(解析网址,获取数据,存储数据)
; N) i( P0 ^) M$ l. N它的整个流程就是:(简单的通过request请求获取数据并解析获取数据。以下都是固定化格式,可以照搬); G( d% ~+ y& x% @
a、导入需要的库 requests4 n; g4 b" x6 d; k8 v
# ?3 z& @' P8 A8 e$ a9 {7 H
import requests
) ~" W' b7 n  K( L+ y1
2 s% q- {( B4 N& \0 ~8 eb、明确你要获取数据的网址(这里以百度网站为例)' U) P# a5 G8 k
% @, b8 T3 E! _
url = 'http://www.baidu.com'* Y2 t' l9 M9 `) P7 H0 Z
1
7 l2 I" p0 P2 {0 gc、创建请求
7 a' o8 s- C, q; {; M* W* ?* \: ?, j; G% r7 X- r5 i
response =  requests.get(url)
/ o1 J' f. p9 k" Q; c& H5 }' X1
& D+ ?/ c# q1 K( R4 {9 k, k/ U( ~d、测试请求是否成功(在实际应用中用的比较少,正常情况都是可以请求成功的,网站对于访问外部信息的爬虫是不会做出限制的)  L8 L% a+ h- _+ \/ K

2 q# t, S6 k; c0 {print("状态码:",response.status_code)* y( X7 h4 X# P- I% B+ b( j$ T
17 A2 F* T3 T. f2 Y% e
当状态码为“200”时表示请求成功;如果不是“200”,很大可能就是你的目标url写错了,核对一下url) D3 c3 ]- K4 B3 l6 ]
e、得到网页源码+ Y7 Q& S) B9 L! B( g6 S8 W0 e! Z8 z! X
( L% Q8 b  z; a5 T7 U/ E
print("内容:",response.text)$ `" J7 R  H) L7 @! @7 l
1" \* A3 q% L+ ]3 ]$ z" G
response.content是response.text的二进制形式
  Q7 J/ M0 Q# W& R% e3 f4 \3 |, ~
+ H6 b4 h2 ^, h% A, T至此,一个简单的爬虫请求就算是完成了。
, |, P$ Y! T* ]. H2 Y, y当我们请求目标url并获取到response后,就需要进行下一步:解析网址并获取数据
3 d( S4 N) R& d6 l1 af、解析网址
$ F3 ^6 c5 u/ ]( q/ N5 Y  K# ?刚开始学习阶段,我们最常用的两种方法,一种是BeautifulSoup,一种是etree。其中BeautifulSoup是最常用的。以下将对两种方法分别进行介绍 (以下方法均为测试用例,实际当中应结合自己的实际情况选择应用)
7 u/ Q: A; K) A3 G0 g. {2 x$ ]3 RBeautifulSoup:
- A2 o7 E: O/ D0 Y; r4 j首先导入需要的库文件:
5 A8 {( i! }# ]+ P( x4 Q
% l3 a7 x* j/ p$ lfrom bs4 import BeautifulSoup
0 i, w% M( t8 Y& s) {1. w1 Q" \$ m) q3 ~6 F% A1 q) r
然后对上面请求得到的response进行解析:
0 J, S! Z) Z% U! ~& J6 O/ _/ ?
2 F8 t3 G  f& m$ W/ |  khtml = respone.content.decode('utf-8')  J$ g7 v. q& N, j7 c  U
soup = BeautifulSoup(html, 'lxml')
6 B1 A+ I7 {% F( z# s( i1
4 _( T1 L- @, V2- ~+ P3 t/ g% Q# [6 U
以下是BeautifulSoup中比较常见的方法,有兴趣的朋友可以去一一测试:" v: G/ l' `5 c: J
# 获取head标签
2 W, J4 v7 M# Z/ W# E/ V( iprint('head标签内容', soup.head)
! z* K+ j8 m9 o/ ~# 获取title标签; V, b" q! J2 d! _3 g% d  m5 }
print('head标签内容', soup.title)
' I; I' ~; V6 P& D/ L0 w5 C5 @( [1 g# 获取body里面的img内容% h3 q* u3 {' w- G8 m6 w% r
# 通过点号的方式只能获取 下属第一个标签(即获取soup下面第一个body里的第一个a标签的第一个img标签)$ ^" h* Z# Z, \: [" W+ `* o
print(soup.body.a.img)   ' S" r; s% Z" D
# 获取所有的img标签  使用find_all()搜索整个soup对象
; v* R* H4 R3 v3 S& D3 lprint("获取所有的img标签", soup.find_all('img'))5 V& O- j5 r0 h+ k3 ~+ N' k5 q
# 获取标签中的属性src地址' g& m) ?7 H7 Q( W% e  g$ |
print("获取标签中的属性src地址:", soup.img['src'])      # 注意:英文点号都只能获取第一个值! a: Z4 k: H# V, r: M4 ]+ k2 ?% j

. z% g, L/ ?! S0 R, b9 _; M9 v0 M5 j2 m9 C9 N
# 获取soup的name
1 O0 L' w- N+ t0 A9 F: Z$ Oprint("获取soup的name:",soup.name)8 k5 T$ i" B3 M6 Q! E
# 获取a标签名
+ w8 U" I( H3 O0 Jprint("a标签名字:",soup.a.name)
7 f- F. Q0 [, `* Otag = soup.a
+ C, \: ?5 c) D" Qprint(tag)( C8 q1 M7 ^. q! k, y- N  X
# 修改操作  a标签改为b标签
( E3 K# A  B  x: Ltag.name = 'b'   # 赋值后<a> </a>变为<b> </b>
1 H& x# s8 M' j. u# 输出修改后的内容
9 z# V" K( t6 |, t* k: F' a) M) Lprint("输出修改后的内容:",tag)
' `3 [+ b, E7 ?+ Q  A6 `$ M# 获取全部的属性 attrs
9 L- o; J; `! pprint("tag对象的全部属性:",tag.attrs)   # 只能得到当前标签的属性(不包含下属标签)
' u+ Q  H2 v0 p# W/ |# D" l6 ~: G) N9 z) j6 a7 Y$ _
# 获取属性的class的值   根据键取值; G( e" Z* H9 n  X; g
print("获取属性的class的值:",tag["class"])
( u3 @& b& {! }% ]; r  @9 K/ t: O
# a* b% S* J  g, H! C3 b/ H1 F9 C$ ^
1 L1 W- H; |7 n4 U, [" d# A6 o+ U
9 ~1 z: y! i; y9 u9 @1 ^2 h9 b7 B& F4 g( Y! a, o9 I! v# A: v
"""针对获取的标签属性可以进行增删改查"""
6 X- @/ [8 s+ r; K# 修改
6 Y9 k4 _$ c1 ftag["class"] = "Logo"
& C  }# D/ F$ ]' i7 B0 }print("tag对象的全部属性:",tag.attrs)- }! u, k) @# v
# 输出属性( A* u. o4 d6 O# v- U4 X5 }
print("获取属性的class的值:",tag["class"]); H$ L2 i# c2 v0 a8 t4 ^& {
# 新增  属性id  赋值logo
' f. D) h8 ?- Utag['id'] = 'logo'
# ?0 K& d0 ]$ T$ l: Oprint("tag对象的全部属性:",tag.attrs). W) b% V% p/ M4 B; x" o8 Q
# 删除属性" D/ q' \; L. s+ ^7 x- j
del tag['class']
/ q4 K' ?  u# ]$ N) q( fprint("tag对象的全部属性:",tag.attrs)1 m0 J- {* {* b! W4 z8 }6 n
  S0 q1 f8 h! w* q) a
+ h6 V: c4 n9 f8 ?9 t( Z3 w1 L" `
+ I: I% t9 M' E& A4 k
"""针对内容操作  (只针对标签,对属性无效)"""
4 N5 e' ]+ L' P2 a8 N! w% E# 获取title标签内容: {: V0 F. d9 J+ W
tag = soup.title4 J# Q$ G4 Z% `, L/ x5 W) \- }& B- I0 k: n
# 获取title字符串
* C2 B" C+ v$ J. Q9 }9 Q! Aprint("tag对象所包含的字符串:", tag.string)
' R" c3 b* O1 B: C7 Q& T4 E* Mprint("类型:", type(tag.string))3 o/ U- L4 b& L; U) O8 |$ |% L& |
# 替换内容' |/ ?9 k* D8 c! I  E( a
tag.string.replace_with("你好")/ _2 H  V' o+ |0 N, m" x% f& [
print(tag.string)
/ e* c' {% s  @" R# <!-- 学科建设 -->
7 c; I1 [  U8 y# 获取注释文本内容
( |' t: Z1 }' q: R6 n8 Emarkup = '<b><!-- 学科建设 --></c>'
+ m! W- G' Y# ^( }5 r# bsoup_comment = BeautifulSoup(markup, 'lxml')
& w2 u8 `& j. |0 S7 o  S: u8 scomment = soup_comment.b.string                    # 以markup第一个标签作为关键进行搜索2 ~8 m6 d; S/ c+ H; e8 ?
print("获取注释文本内容:", comment)) \6 j8 ~8 Y" I4 L7 Y9 A
# get_text()
$ B) Z3 x! d' u' }print("title的全部节点:",soup.find_all("title"))$ N1 v' `6 b7 m: N* ~7 c' N
print("title的内容:",soup.title.get_text())/ u$ P/ ?$ N! S) T/ R. f+ e+ N
"""查找ul元素标签"""
# D  I" [4 m# M) c# class是关键名,匹配时后面必须加下划线_
& U! U' c  G/ O$ V& U# tag = soup.find_all("ul", class_='menu')  # 按照css类名完全匹配
' ~5 g  ?1 Y; ~6 n( @: a+ u# print(tag)
$ q; G1 @* E/ Y: {% Gtag = soup.find_all("ul", id='menu')  # 按照css类名完全匹配
5 _0 F' Y: ^& w# ], ]print(tag)
) a- m0 m, a, Z# u& J# 查找名称为a元素的标签内容0 [) @- [! C- W
taga = soup.find_all('a')
5 h# [! U+ l# G7 \7 Qfor tag in taga:
/ ]3 g! S" L2 V2 l9 V5 w    print("查找名称为a元素的标签内容:", tag.string)
9 _5 u3 e7 L+ w- L$ ]( G, N: h' \5 D# get 获取属性信息  获取整个页面的img标签图片和src属性值7 E8 z. Z! m! y1 ^3 p* h
tagings = soup.find_all('img')
' l* r1 V: N2 H3 w5 i4 C. v/ U; `- eprint(tagings)
( Q4 r: l0 U2 i' g, {0 G2 p. b. c# 循环输出图片地址
! @8 H2 X: y2 G1 Rfor imgsrc in tagings:3 v7 ~. j* b. p/ d: W, O# s) c
    print(url+imgsrc.get('src'))
9 Q0 k. g# y- U$ Y
) K# E( F! Q! L! N" z; w""""属性只能做为参数,所有的操作只能针对标签"""+ z& ^" v* P6 r9 O- ~: G
7 `0 r. L; {7 j: L' q1 F2 _9 k# u
etree方法:
5 R! D  m9 }8 I+ D- q  [8 @4 i导入库文件:
0 R2 t1 T& n, y% ~# l+ N) G6 w- @' m1 n" `8 B+ Z5 l$ v* }
from lxml import etree
2 b$ v8 d9 `+ ?/ N" g1
; T6 F9 Z: F  h5 ]- D. a1 h4 E解析得到的response对象;
' F& m! {; p  O" r$ n# H: V" s1 r7 u) v9 _
# 设置response的字符集8 g% O8 \; w8 I% X/ O* Y/ p; b
html = req.content.decode('utf-8')
. B9 h  q% G. c/ w, M7 P# 解析对象: b- b* t: T/ n- d4 {) |- h; Q8 @
html = etree.HTML(html,parser=etree.HTMLParser(encoding='utf-8'))9 ~1 H& k/ j; a1 t3 R2 l7 {# s  V

! Q- @! \" K5 t- {; t" E" u* ^常用的方法:
- }* ]8 D. _3 m) l$ k( q7 B) h' V- W
5 v' c) o# _% Y# k
# 定位head节点(元素)
' ]: ?2 z9 ~! E) `& W& |0 N; aresult1 = html.xpath('head')
+ g9 A" K+ G7 R5 K& tprint(result1)3 ?: c  @; d) E) I& R
# 定位title节点
2 {; B9 @4 c3 [; z+ `0 Zresult2 = html.xpath('/html/head/title')
2 v7 m" }! s3 Hprint(result2)$ W' T1 L% o- k, ]
# 搜索节点  title节点. ?. t# c6 F! u0 C
result3 = html.xpath('//title')
* l. f8 m4 u' G: Kprint(result3)
. Q) [6 _, ]5 K$ Y1 L, n$ k7 }# 搜索title内容  text()得到文本信息
' r3 U2 L, Q9 @6 `+ X2 sresult4 = html.xpath("//title/text()")) x/ R' X. P$ n  E3 Z
print(result4)
8 I/ C: ~7 x$ z$ J2 p4 V# 搜索div节点' i0 t2 r) e  D: ^# l7 y9 [+ }
result5 = html.xpath('//div')
# I# _0 w+ x: I3 _8 [# e1 uprint(result5)5 l3 z& w, S1 ?% D0 p
# 搜索div节点 并用class属性定位
; L/ j' K' n3 D3 h2 wresult6 = html.xpath('//div[@class="news"]')
/ p- @. q* c' l6 m: A) Y2 jprint(result6)
' E* @' @: m! T7 `$ r# 搜索div节点 id属性定位0 ^$ Z; U% L9 O7 k; ?- b
result7 = html.xpath('//div[@id="news"]')
3 f3 g3 f" f4 fprint(result7)
/ J/ d+ F/ L: D# P7 F* E# 获取列表span信息
$ j5 h8 P* U6 @. O: z3 b. U+ D7 Ttext = html.xpath('//div[@class="news"]/a/span/text()')4 L7 U( S! @* ?
print(text)9 }3 z6 j# }& m. U

) P% o& A/ n6 z* m) u' m' D" j

g、通过上一步我们得到自己需要的数据后,下一步就是将我们得到的数据进行保存) i3 d: ^" M5 v* d# Y
保存的方式有很多种:' ~1 q6 |, c! Q) |
1、保存至文件
. p$ ?4 M* A  `9 m2 bcsv、json、text3 t+ a7 T/ a. `: Q+ o- V" l
2、保存至数据库$ y0 r% n5 ~# H: t# w$ h! S
MySql、MongoDB、Redis 等 (目前主流的为以上列举的三种数据库)

关于数据存储后面再做详细介绍% i+ V6 u/ K' J7 X7 ^6 k

; s, J7 M( d& X- L0 n7 p& }! `0 \, }! L6 d8 Z7 c9 u
————————————————4 o8 a( S  K, W
版权声明:本文为CSDN博主「royallucky」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
- C; B/ x; K% r" E7 Q7 P原文链接:https://blog.csdn.net/royallucky/article/details/105930473; q+ |. o' q% R7 D- U% R2 N

2 u1 s% @9 d' l6 @
% o7 l. Y% A3 f% q. x) S7 p
作者: 建模小白12138    时间: 2020-5-5 20:43
感谢楼主,,,,,,,,,,,,,,。9 c' z  i+ ^& U1 N. A  `





欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) Powered by Discuz! X2.5