zoukankan      html  css  js  c++  java
  • Python 基础教程 —— 网络爬虫入门篇

    前言 

    Python 是一种解释型、面向对象、动态数据类型的高级程序设计语言,它由 Guido van Rossum 于 1989 年底发明,第一个公开发行版发行于 1991 年。
    自面世以后,Python 深受广大开发者的喜迎,在网站开发,网络爬虫,数据分析,机器学习,人工智能等领域都有其过人之处。
    在“Python基础教程“中,本人将会从各个不同领域介绍Python的用法,今天就先从最常用的网络爬虫开始说起。
    网络爬虫主要目的是通过定期收集网络的信息,把信息保存后进行分析归类,最后通过报表显示给相关的用户作为业务参考。几年我也曾经做过一个项目是对税务局的政府网站进行信息收集,把收集到的税务政策,各行业的税率变动,国家颁布的新行税法进行分析,把分析结果综合到财税管理平台进行财务核算。
    为了简化流程,这次就以常用的天气网为例子(http://www.weather.com.cn/),定时收集地区的天气情况,最后把数据作为图表显示。

    目录

    一、页面下载

    二、数据读取

    三、数据保存

    四、使用 matplotlib 显示数据

    五、定时器

    一、页面下载

    这里用到了 urllib 库里面的 request 类,它有两个常用的方法:

    1.  urlretrieve 用于下载网页

    1 def urlretrieve(url: str,
    2       filename: Optional[str] = ...,
    3       reporthook: Optional[(int, int, int) -> None] = ...,
    4       data: Optional[bytes] = ...)

    参数说明

    url:网页地址 url
    filename:指定了保存到本地的路径(如果未指定该参数,urllib会生成一个临时文件来保存数据);
    reporthook:是一个回调函数,当连接上服务器、以及相应的数据块传输完毕的时候会触发该回调。我们可以利用这个回调函数来显示当前的下载进度。
    data:指post到服务器的数据。该方法返回一个包含两个元素的元组(filename, headers),filename表示保存到本地的路径,header表示服务器的响应头。

    2. urlopen 可以像打开文档一样直接打开远程页面,区别在于 urlopen是只读模式

    1 def urlopen(url: Union[str, Request],
    2             data: Optional[bytes] = ...,
    3             timeout: Optional[float] = ...,
    4             *,
    5             cafile: Optional[str] = ...,
    6             capath: Optional[str] = ...,
    7             cadefault: bool = ...,
    8             context: Optional[SSLContext] = ...)

     参数说明

     url :目标资源在网路中的位置。可以是一个表示URL的字符串,也可以是一个urllib.request对象,详细介绍请跳转

    data:data用来指明发往服务器请求中的额外的参数信息(如:在线翻译,在线答题等提交的内容),data默认是None,此时以GET方式发送请求;当用户给出data参数的时候,改为POST方式发送请求。

    timeout:设置网站的访问超时时间

    cafile、capath、cadefault:用于实现可信任的CA证书的HTTP请求。(基本上很少用)

    context参数:实现SSL加密传输。

     1 class Weather():
     2 
     3     def __init__(self):
     4         #确定下载路径,以日期作为文件名
     5         self.path='E:/Python_Projects/Test/weather/'
     6         self.filename=str(datetime.date.today()).replace('-','')
     7 
     8     def getPage(self,url):
     9         #下载页面并保存
    10         file=self.path+self.filename+'.html'
    11         urlretrieve(url,file,None,None)

     运行方法后可以看到在文件夹里已经保存了整个静态页面

    回到目录

    二、数据读取

    因为每个html页面的数据均有不同,我们可以观察html代码的特征,通过 re 的功能找到所需要的数据。
    这里介绍几个 re 常用的方法

    1、re.compile(pattern,flags = 0 )

    将正则表达式模式编译为正则表达式对象,可使用match(),search()以及下面所述的其他方法将其用于匹配

    2、re.search(pattern,string,flags = 0 )

    扫描字符串以查找正则表达式模式产生匹配项的第一个位置 ,然后返回相应的match对象。None如果字符串中没有位置与模式匹配,则返回;否则返回false。请注意,这与在字符串中的某个点找到零长度匹配不同。

    3、re.match(pattern,string,flags = 0 )

    如果字符串开头的零个或多个字符与正则表达式模式匹配,则返回相应的匹配对象。None如果字符串与模式不匹配,则返回;否则返回false。请注意,这与零长度匹配不同。

    4、re.fullmatch(pattern,string,flags = 0 )

    如果整个字符串与正则表达式模式匹配,则返回相应的match对象。None如果字符串与模式不匹配,则返回;否则返回false。请注意,这与零长度匹配不同。

    5、re.split(pattern,string,maxsplit = 0,flags = 0 )

    通过出现模式来拆分字符串。如果在pattern中使用了捕获括号,那么模式中所有组的文本也将作为结果列表的一部分返回。如果maxsplit不为零,则最多会发生maxsplit分割,并将字符串的其余部分作为列表的最后一个元素返回。

    6、re.findall(pattern,string,flags = 0 )

    以string列表形式返回string中pattern的所有非重叠匹配项。从左到右扫描该字符串,并以找到的顺序返回匹配项。如果该模式中存在一个或多个组,则返回一个组列表;否则,返回一个列表。如果模式包含多个组,则这将是一个元组列表。空匹配项包含在结果中。

    7、re.finditer(pattern,string,flags = 0 )

    返回一个迭代器,该迭代器在string类型的RE 模式的所有非重叠匹配中产生匹配对象。 从左到右扫描该字符串,并以找到的顺序返回匹配项。空匹配项包含在结果中。

    本例子比较简单,可以看到在地区白天/夜晚的气温都包含在  <p class="tem"><span>30</span><em>°C</em></p>,可以直接通过 re.compile() 找到数据。

    然而在不同的页面里,数据可能是通过后台绑定,或者在页面渲染时绑定,这时候就需要细心地找寻数据来源,再通过链接获取。

     1     def readPage(self):
     2         #读取页面
     3         file=open(self.path+self.filename+'.html','r',1024,'utf8')
     4         data=file.readlines()
     5         #找出当天白天温度与晚上温度
     6         pat=re.compile('<span>[0-9][0-9]</span>')
     7         data=re.findall(pat,str(data))
     8         file.close()
     9         #筛选温度值,返回list
    10         list1 = []
    11         for weather in data:
    12             w1 = weather.replace('<span>', '')
    13             w2 = w1.replace('</span>', '')
    14             list1.append(w2) 
    15         return list1

    最后返回 list 数组,其中包含当天的日间气温与夜间气温

    回到目录

    三、数据保存

    把当天日期、日间气温、夜间气温保存到数据库

     1     def save(self,list1):
     2         #保存到数据库
     3         db = MySQLdb.connect("localhost", "root", "********", "database", charset='utf8')
     4         cursor = db.cursor()
     5         sql = 'INSERT INTO weather(date,daytime,night) VALUES ('+self.filename+','+list1[0]+','+list1[1]+')'
     6         try:
     7             cursor.execute(sql)
     8             db.commit()
     9         except:
    10             # 发生错误时回滚
    11             db.rollback()
    12         # 关闭数据库连接
    13         db.close()

     回到目录

    四、使用 matplotlib 显示数据

    在数据库积累多天数据后,通过 matplotlib 库显示数据

     1 def display():
     2     # X轴旋转90度
     3     plt.xticks(rotation=90)
     4     # 从数据库中获取数据
     5     db = MySQLdb.connect("localhost", "root", "********", "database", charset='utf8')
     6     cursor = db.cursor()
     7     sql = 'SELECT date,daytime,night FROM weather'
     8     try:
     9         cursor.execute(sql)
    10         data=np.array(cursor.fetchall())
    11         db.commit()
    12     except:
    13         # 发生错误时回滚
    14         db.rollback()
    15     #数据转换成日期数组,白天温度数组,夜间温度数组
    16     if len(data)!=0:
    17         date=data[:,0]
    18         # y轴数据需要转化为int形式,否则将按字符串形式排列
    19         daytime=(np.int16(data[:,1]))
    20         night=(np.int16(data[:,2]))
    21         plt.xlabel('Date')
    22         plt.ylabel('Temperature')
    23         plt.title('Weather')
    24         # 显示数据
    25         plt.plot(date,daytime,label='day')
    26         plt.plot(date,night,label='night')
    27         plt.legend()
    28         plt.show()

    显示结果

    回到目录

    五、定时器

    使用 Timer 定时器每天执行一次,下载数据,再刷新画面

     1 def start():
     2     weather=Weather()
     3     weather.getPage(url)
     4     data=weather.readPage()
     5     weather.save(data)
     6     display()
     7     t = threading.Timer(86400, start)
     8     t.start()
     9 
    10 url='http://www.weather.com.cn/weather1d/101280101.shtml'
    11 if __name__ == '__main__':
    12     start()

    回到目录

    全部源代码

     1 from urllib.request import urlretrieve,urlopen
     2 from matplotlib import pyplot as plt
     3 
     4 import numpy as np,threading,re,datetime,MySQLdb
     5 
     6 class Weather():
     7 
     8     def __init__(self):
     9         #确定下载路径,以日期作为文件名
    10         self.path='E:/Python_Projects/Test/weather/'
    11         self.filename=str(datetime.date.today()).replace('-','')
    12 
    13     def getPage(self,url):
    14         #下载页面并保存
    15         file=self.path+self.filename+'.html'
    16         urlretrieve(url,file,None,None)
    17 
    18     def readPage(self):
    19         #读取页面
    20         file=open(self.path+self.filename+'.html','r',1024,'utf8')
    21         data=file.readlines()
    22         #找出当天白天温度与晚上温度
    23         pat=re.compile('<span>[0-9][0-9]</span>')
    24         data=re.findall(pat,str(data))
    25         file.close()
    26         #筛选温度值,返回list
    27         list1 = []
    28         for weather in data:
    29             w1 = weather.replace('<span>', '')
    30             w2 = w1.replace('</span>', '')
    31             list1.append(w2)  # 保存数据
    32         return list1
    33 
    34     def save(self,list1):
    35         #保存到数据库
    36         db = MySQLdb.connect("localhost", "root", "********", "database", charset='utf8')
    37         cursor = db.cursor()
    38         sql = 'INSERT INTO weather(date,daytime,night) VALUES ('+self.filename+','+list1[0]+','+list1[1]+')'
    39         try:
    40             cursor.execute(sql)
    41             db.commit()
    42         except:
    43             # 发生错误时回滚
    44             db.rollback()
    45         # 关闭数据库连接
    46         db.close()
    47 
    48 def display():
    49     # X轴旋转90度
    50     plt.xticks(rotation=90)
    51     # 从数据库中获取数据
    52     db = MySQLdb.connect("localhost", "root", "********", "database", charset='utf8')
    53     cursor = db.cursor()
    54     sql = 'SELECT date,daytime,night FROM weather'
    55     try:
    56         cursor.execute(sql)
    57         data=np.array(cursor.fetchall())
    58         db.commit()
    59     except:
    60         # 发生错误时回滚
    61         db.rollback()
    62     #数据转换成日期数组,白天温度数组,夜间温度数组
    63     if len(data)!=0:
    64         date=data[:,0]
    65         # y轴数据需要转化为int形式,否则将按字符串形式排列
    66         daytime=(np.int16(data[:,1]))
    67         night=(np.int16(data[:,2]))
    68         plt.xlabel('Date')
    69         plt.ylabel('Temperature')
    70         plt.title('Weather')
    71         # 显示数据
    72         plt.plot(date,daytime,label='day')
    73         plt.plot(date,night,label='night')
    74         plt.legend()
    75         plt.show()
    76 
    77 def start():
    78     weather=Weather()
    79     weather.getPage(url)
    80     data=weather.readPage()
    81     weather.save(data)
    82     display()
    83     t = threading.Timer(86400, start)
    84     t.start()
    85 
    86 url='http://www.weather.com.cn/weather1d/101280101.shtml'
    87 if __name__ == '__main__':
    88     start()
    View Code

    总结

    这个例子只是从最简单的角度介绍爬虫的使用方式,对应实际的应用场景只是冰山一角,在现实中经常还会遇到IP地址被封,数据绑定无法直接获取,数据加密等诸多问题,在后面再作详细介绍。
    由于时间紧迫,文章中有所缺漏的地方敬请点评。

    对 .Python  开发有兴趣的朋友欢迎加入QQ群:790518786 共同探讨 !
    对 JAVA 开发有兴趣的朋友欢迎加入QQ群:174850571 共同探讨!
    对 .NET  开发有兴趣的朋友欢迎加入QQ群:162338858 共同探讨 !

    Python 基础教程

    网络爬虫入门篇

    Pandas 库常用方法实例说明 

    作者:风尘浪子

    https://www.cnblogs.com/leslies2/p/14719516.html

    原创作品,转载时请注明作者及出处

  • 相关阅读:
    vue简单 tabbar封装
    Vue自定义指令实例(实时时间转换指令)
    flutter-搜索条
    flutter-保持页面的效果
    flutter-毛玻璃的效果(很消耗性能)
    flutter-路由跳转动画效果(渐隐渐现,缩放效果,旋转缩放)
    flutter-底部导航&不规则导航
    flutter-异步请求选择回来的方法
    flutter-一般页面导航和返回(传递和接收参数)
    flutter-卡片组件布局
  • 原文地址:https://www.cnblogs.com/leslies2/p/14719516.html
Copyright © 2011-2022 走看看