spider-01

文章目录

Day01笔记

概述

【1】定义
    1.1) 网络蜘蛛、网络机器人,抓取网络数据的程序
    1.2) 其实就是用Python程序模仿人点击浏览器并访问网站,而且模仿的越逼真越好

【2】爬取数据的目的
    2.1) 公司项目的测试数据,公司业务所需数据
    2.2) 获取大量数据,用来做数据分析

【3】企业获取数据方式
    3.1) 公司自有数据
    3.2) 第三方数据平台购买(数据堂、贵阳大数据交易所)
    3.3) 爬虫爬取数据

【4】Python做爬虫优势
    4.1) Python :请求模块、解析模块丰富成熟,强大的Scrapy网络爬虫框架
    4.2) PHP :对多线程、异步支持不太好
    4.3) JAVA:代码笨重,代码量大
    4.4) C/C++:虽然效率高,但是代码成型慢

【5】爬虫分类
    5.1) 通用网络爬虫(搜索引擎使用,遵守robots协议)
        robots协议: 网站通过robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取,通用网络爬虫需要遵守robots协议(君子协议)
	    示例: https://www.baidu.com/robots.txt
    5.2) 聚焦网络爬虫 :自己写的爬虫程序

【6】爬取数据步骤
    6.1) 确定需要爬取的URL地址
    6.2) 由请求模块向URL地址发出请求,并得到网站的响应
    6.3) 从响应内容中提取所需数据
       a> 所需数据,保存
       b> 页面中有其他需要继续跟进的URL地址,继续第2步去发请求,如此循环
  • 重大问题思考

    网站如何来判定是人类正常访问还是爬虫程序访问?–检查请求头!!!

    # 请求头(headers)中的 User-Agent
    # 测试案例: 向测试网站http://httpbin.org/get发请求,查看请求头(User-Agent)
    import requests
    
    url = 'http://httpbin.org/get'
    res = requests.get(url=url)
    html = res.text
    print(html)
    # 请求头中:User-Agent为-> python-requests/2.22.0 那第一个被网站干掉的是谁???我们是不是需要发送请求时重构一下User-Agent???添加 headers 参数!!!
    
  • 重大问题解决

    """
    包装好请求头后,向测试网站发请求,并验证
    养成好习惯,发送请求携带请求头,重构User-Agent    User-Agent参数详解
    """
    import requests
    
    url = 'http://httpbin.org/get'
    headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1'}
    html = requests.get(url=url,headers=headers).content.decode('utf-8','ignore')  # 'ignore' 忽略无法转码的字符串 防止网页中带有无法识别字符串而报错
    # Uni codeDecodeError: utf-8 xxx cannot decode char \xxx in.
    	ignore 可解决
    # UnicodeEncodeError: gbk code cannot encode char \xxx in,
    	windows 写入文件时常报错误
        # with open('xxx. txt', 'w’, encoding='gb18030') as f:
    print(html)
    
  • 小总结

    【1】 什么是robots协议,爬虫分为通用网络爬虫和聚焦网络爬虫,只有通用爬虫需要遵守协议
    【2】 requests模块使用
        res = requests.get(url=url,headers={'User-Agent':'xxx'})
        响应对象res属性:
            a> res.text		# 字符串文本
            b> res.content	# 二进制文本
            c> res.status_code	# 响应码
            d> res.url		# 真实url
    【3】网站乱码解析
    方法1:
    	res = requests.get(url=url, headers=headers)
        res.encoding = 'utf-8'
        file.write(res.text)
    方法2:  #  推荐使用方式
    	获取bytes数据,手动转码
    	requests.get(url=url, headers=headers).content.decode('utf-8')
    

正则解析模块re

re模块使用流程

# 方法一 
r_list=re.findall('正则表达式',html,re.S)
# re.S 让正则的.能够匹配\n换行符

# 方法二
pattern = re.compile('正则表达式',re.S)
r_list = pattern.findall(html)
  • 思考 - 请写出匹配任意一个字符的正则表达式?

    import re
    # 方法一
    pattern = re.compile('[\s\S]')
    result = pattern.findall(html)
    
    # 方法二
    pattern = re.compile('.',re.S)
    result = pattern.findall(html)
    
  • 代码示例

    import re
    
    html = '''
    <div><p>九霄龙吟惊天变</p></div>
    <div><p>风云际会潜水游</p></div>
    '''
    # 贪婪匹配
    p = re.compile('<div><p>.*</p></div>',re.S)
    r_list = p.findall(html)
    print(r_list)
    
    # 非贪婪匹配
    p = re.compile('<div><p>.*?</p></div>',re.S)
    r_list = p.findall(html)
    print(r_list)
    

正则表达式分组

  • 作用

    在完整的模式中定义子模式,将每个圆括号中子模式匹配出来的结果提取出来
    
  • 示例代码

    import re
    
    s = 'A B C D'
    p1 = re.compile('\w+\s+\w+')
    print(p1.findall(s))
    # 分析结果是什么???
    # ['A B', 'C D']
    
    p2 = re.compile('(\w+)\s+\w+')
    print(p2.findall(s))
    # 第一步: ['A B', 'C D']
    # 第二步: ['A', 'C']
    
    
    p3 = re.compile('(\w+)\s+(\w+)')
    print(p3.findall(s))
    # 第一步: ['A B', 'C D']
    # 第二步: [('A','B'), ('C','D')]
    
  • 分组总结

    1、在网页中,想要什么内容,就加()
    2、先按整体正则匹配,然后再提取分组()中的内容
       如果有2个及以上分组(),则结果中以元组形式显示 [(),(),()]
    
  • 课堂练习

    # 从如下html代码结构中完成如下内容信息的提取:
    问题1 :[('Tiger',' Two...'),('Rabbit','Small..')]
    问题2 :
    	动物名称 :Tiger
    	动物描述 :Two tigers two tigers run fast
        **********************************************
    	动物名称 :Rabbit
    	动物描述 :Small white rabbit white and white
    
  • 页面结构如下

    <div class="animal">
        <p class="name">
    			<a title="Tiger"></a>
        </p>
        <p class="content">
    			Two tigers two tigers run fast
        </p>
    </div>
    
    <div class="animal">
        <p class="name">
    			<a title="Rabbit"></a>
        </p>
    
        <p class="content">
    			Small white rabbit white and white
        </p>
    </div>
    
  • 练习答案

    import re
    
    html = '''<div class="animal">
        <p class="name">
            <a title="Tiger"></a>
        </p>
    
        <p class="content">
            Two tigers two tigers run fast
        </p>
    </div>
    
    <div class="animal">
        <p class="name">
            <a title="Rabbit"></a>
        </p>
    
        <p class="content">
            Small white rabbit white and white
        </p>
    </div>'''
    
    p = re.compile('<div class="animal">.*?title="(.*?)".*?content">(.*?)</p>.*?</div>',re.S)
    r_list = p.findall(html)
    
    for rt in r_list:
        print('动物名称:',rt[0].strip())   # strip() 去掉字符串两头的空白包括\n\t和空格
        print('动物描述:',rt[1].strip())
        print('*' * 50)
    
        
    # 把想要提取的数据先复制出来,再按需删除,删除的地方加上.*?,需要提取的地方加(.*?)
    

猫眼电影top100抓取案例

  • 爬虫需求

    【1】确定URL地址
        百度搜索 - 猫眼电影 - 榜单 - top100榜
    
    【2】 爬取目标
        所有电影的 电影名称、主演、上映时间
    
  • 爬虫实现

    【1】查看网页源码,确认数据来源
        响应内容中存在所需抓取数据 - 电影名称、主演、上映时间
    
    【2】翻页寻找URL地址规律
        第1页:https://maoyan.com/board/4?offset=0
        第2页:https://maoyan.com/board/4?offset=10
        第n页:offset=(n-1)*10
    
    【3】编写正则表达式
        <div class="movie-item-info">.*?title="(.*?)".*?class="star">(.*?)</p>.*?releasetime">(.*?)</p>
        
    【4】开干吧兄弟
    
  • 代码实现

    """
    猫眼电影top100抓取(电影名称、主演、上映时间)
    """
    import requests
    import re
    import time
    import random
    
    class MaoyanSpider:
        def __init__(self):
            self.url = 'https://maoyan.com/board/4?offset={}'
            self.headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko'}
    
        def get_html(self, url):
            html = requests.get(url=url, headers=self.headers).text
            # 直接调用解析函数
            self.parse_html(html)
    
        def parse_html(self, html):
            """解析提取数据"""
            regex = '<div class="movie-item-info">.*?title="(.*?)".*?<p class="star">(.*?)</p>.*?<p class="releasetime">(.*?)</p>'
            pattern = re.compile(regex, re.S)
            r_list = pattern.findall(html)
            # r_list: [('活着','牛犇','2000-01-01'),(),(),...,()]
            self.save_html(r_list)
    
        def save_html(self, r_list):
            """数据处理函数"""
            item = {}
            for r in r_list:
                item['name'] = r[0].strip()
                item['star'] = r[1].strip()
                item['time'] = r[2].strip()
                print(item)
    
        def run(self):
            """程序入口函数"""
            for offset in range(0, 91, 10):
                url = self.url.format(offset)
                self.get_html(url=url)
                # 控制数据抓取频率:uniform()生成指定范围内的浮点数
                time.sleep(random.uniform(0,1))
    
    if __name__ == '__main__':
        spider = MaoyanSpider()
        spider.run()
    

数据持久化 - MySQL

  • pymysql回顾

    import pymysql
    
    db = pymysql.connect('localhost','root','123456','maoyandb',charset='utf8')
    cursor = db.cursor()
    
    ins = 'insert into filmtab values(%s,%s,%s)'
    cursor.execute(ins,['霸王别姬','张国荣','1993'])
    
    db.commit()
    cursor.close()
    db.close()
    
  • 练习 - 将电影信息存入MySQL数据库

    【1】提前建库建表
    mysql -h127.0.0.1 -uroot -p123456
    create database maoyandb charset utf8;
    use maoyandb;
    create table maoyantab(
    name varchar(100),
    star varchar(300),
    time varchar(100)
    )charset=utf8;
    
    【2】 使用excute()方法将数据存入数据库思路
        2.1) 在 __init__() 中连接数据库并创建游标对象
        2.2) 在 save_html() 中将所抓取的数据处理成列表,使用execute()方法写入
        2.3) 在run() 中等数据抓取完成后关闭游标及断开数据库连接
    
  • 汽车之家二手车信息抓取

    【1】URL地址
        进入汽车之家官网,点击 二手车
        即:https://www.che168.com/beijing/a0_0msdgscncgpi1lto1cspexx0/
            
    【2】抓取目标
        每辆汽车的
        2.1) 汽车名称
        2.2) 行驶里程
        2.3) 城市
        2.4) 个人还是商家
        2.5) 价格
        
    【3】抓取前5页
    
  • 参考答案

    import requests
    import re
    import time
    import random
    
    class CarSpider:
        def __init__(self):
            self.url = 'https://www.che168.com/beijing/a0_0msdgscncgpi1lto1csp{}exx0/?pvareaid=102179#currengpostion'
            self.headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36'}
    
        def get_html(self, url):
            html = requests.get(url=url, headers=self.headers).content.decode('gb2312', 'ignore')
            self.parse_html(html)
    
        def parse_html(self, html):
            pattern = re.compile('<li class="cards-li list-photo-li".*?<div class="cards-bottom">.*?<h4 class="card-name">(.*?)</h4>.*?<p class="cards-unit">(.*?)</p>.*?<span class="pirce"><em>(.*?)</em>', re.S)
            car_list = pattern.findall(html)
            self.save_html(car_list)
    
        def save_html(self, car_list):
            for car in car_list:
                print(car)
    
        def run(self):
            for i in range(1,6):
                page_url = self.url.format(i)
                self.get_html(page_url)
                time.sleep(random.randint(1,2))
    
    if __name__ == '__main__':
        spider = CarSpider()
        spider.run()
    

请求模块(requests)

html = requests.get(url=url,headers=headers).text
html = requests.get(url=url,headers=headers).content.decode('utf-8')

with open('xxx.txt','w',encoding='utf-8') as f:
    f.write(html)

解析模块(re)

  • 使用流程

    p = re.compile('正则表达式',re.S)
    r_list = p.findall(html)
    
  • 贪婪匹配和非贪婪匹配

    贪婪匹配(默认) : .*
    非贪婪匹配     : .*?
    
  • 正则表达式分组

    【1】想要什么内容在正则表达式中加()
    【2】多个分组,先按整体正则匹配,然后再提取()中数据。结果:[(),(),(),(),()]
    

抓取步骤

【1】确定所抓取数据在响应中是否存在(右键 - 查看网页源码 - 搜索关键字)
【2】数据存在: 查看URL地址规律
【3】写正则表达式,来匹配数据
【4】程序结构
	a>每爬取1个页面后随机休眠一段时间
# 程序结构
class xxxSpider(object):
    def __init__(self):
        # 定义常用变量,url,headers及计数等
        
    def get_html(self):
        # 获取响应内容函数,使用随机User-Agent
    
    def parse_html(self):
        # 使用正则表达式来解析页面,提取数据
    
    def save_html(self):
        # 将提取的数据按要求保存,csv、MySQL数据库等
        
    def run(self):
        # 程序入口函数,用来控制整体逻辑
        
if __name__ == '__main__':
    # 程序开始运行时间戳
    start = time.time()
    spider = xxxSpider()
    spider.run()
    # 程序运行结束时间戳
    end = time.time()
    print('执行时间:%.2f' % (end-start))
上一篇:【LabVIEW】二进制文件的存储与读取方法


下一篇:第十一章 封装/继承/多态