python爬虫入门 之 移动端数据的爬取

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python爬虫入门 之 移动端数据的爬取相关的知识,希望对你有一定的参考价值。

第七章 移动端数据的爬取

  • 基于某一款抓包工具 : fiddler ,青花瓷 ,miteproxy

7.1 fiddler 基本配置

7.1.1fiddler简介和安装

  • 什么是Fiddler?

    • Fiddler是位于客户端和服务器端的HTTP代理,也是目前最常用的http抓包工具之一 。 它能够记录客户端和服务器之间的所有 HTTP请求,可以针对特定的HTTP请求,分析请求数据、设置断点、调试web应用、修改请求的数据,甚至可以修改服务器返回的数据,功能非常强大,是web调试的利器。

  • Fiddler安装

7.1.2手机APP抓包设置

  • Fiddler设置打开Fiddler软件,打开工具的设置。(Fiddler软件菜单栏:Tools->Options)在HTTPS中设置如下:

  • 在Connections中设置如下

    • 这里使用默认8888端口,当然也可以自己更改,但是注意不要与已经使用的端口冲突:Allow remote computers to connect:允许别的机器把请求发送到fiddler上来

  • 安全证书下载

    • 在电脑浏览器中输入地址:http://localhost:8888/,点击FiddlerRoot certificate,下载安全证书:

  • 安全证书安装

    • 证书是需要在手机上进行安装的,这样在电脑Fiddler软件抓包的时候,手机使用电脑的网卡上网才不会报错。

  • Android手机安装:

    • 把证书放入手机的内置或外置存储卡上,然后通过手机的"系统安全-》从存储设备安装"菜单安装证书。然后找到拷贝的FiddlerRoot.cer进行安装即可。安装好之后,可以在信任的凭证中找到我们已经安装好的安全证书。

  • 苹果手机安装:

    • 保证手机网络和fiddler所在机器网络是同一个网段下的在safari中访问http://fiddle机器ip:fiddler端口,进行证书下载。然后进行安装证书操作。在手机中的设置-》通用-》关于本机-》证书信任设置-》开启fiddler证书信任

  • 局域网设置 想要使用Fiddler进行手机抓包,首先要确保手机和电脑的网络在一个内网中,可以使用让电脑和手机都连接同一个路由器。当然,也可以让电脑开放WIFI热点,手机连入。这里,我使用的方法是,让手机和电脑同时连入一个路由器中。最后,让手机使用电脑的代理IP进行上网。 在手机上,点击连接的WIFI进行网络修改,添加代理。进行手动设置,ip和端口号都是fiddler机器的ip和fiddler上设置的端口号。

  • Fiddler手机抓包测试

    • 上述步骤都设置完成之后,用手机浏览器打开百度首页,我们就可以顺利抓包了

7.1.3移动端数据的捕获流程

  • tools --> options --> connection -->allow remote

  • http: fiddler所在pc机的ip :8888/ 访问到一张提供了证书下载功能的界面

  • fiddler所在机器和手机在同一网段下 :在手机上浏览器中访问 http: fiddler所在pc机的ip :8888 获取子页面进行证书的下载和安装(证书信任的操作)

  • 配置你手机的代理 :将手机的代理配置成 fiddler所对应的pc机的ip和手机自己的端口

  • 就可以让fiddler捕获手机发起的http和https的请求

7.2 scrapy ,pyspider

#总结:
#爬虫文件中的属性和方法
    name :爬虫文件唯一标识
    start_url:该列表中的url会被自动的进行请求发送
#自动请求发送的过程:
    def start_requests(self):
        for url in self.start_urls:
            yield scrapy.Request(url,callback=self.parse)
​
#数据解析:
    scrapy中封装的xpath进行数据解析   
    
#scrapy中的xpath 和 etree中的xpath的区别
    scrapy的xpath进行数据解析后返回的列表元素为Selector对象,extract或extract_first这两个方法将Selector对象中对应的数据取出
View Code

7.2.1Scrapy简介

  • 什么是框架?如何学习

    • 框架就是一个集成各种功能且具有很强通用性(可以被应用在各种不同的需求中)的一个项目模板

    • 我们只需要学习框架中封装好的相关功能即可

  • scrapy 集成的功能

    • 高性能的数据解析操作 ,持久化存储,高性能的数据下载操作......

  • 环境的安装(windows)

7.2.2 scrapy的基本使用

  • 创建一个工程 :scrapy startproject firstBlood

    • 项目结构:

      project_name/
         scrapy.cfg:            #项目的主配置信息。(真正爬虫相关的配置信息在settings.py文件中)
         project_name/
             __init__.py  
             items.py            #设置数据存储模板,用于结构化数据,如:Django的Model
             pipelines.py        #数据持久化处理
             settings.py         #配置文件,如:递归的层数、并发数,延迟下载等
             spiders/            #爬虫目录,如:创建文件,编写爬虫解析规则
                 __init__.py
  • 创建爬虫应用程序:(必须在spider这个目录下创建一个爬虫文件)

    • cd proName

    • scrapy genspider spiderName www.xx.com

  • 编写爬虫文件:在步骤2执行完毕后,会在项目的spiders中生成一个应用名的py爬虫文件

    import scrapy
    
    class FirstSpider(scrapy.Spider):
        #爬虫文件的名称:爬虫文件的唯一标识(在spiders子目录下是可以创建多个爬虫文件)
        name = \'first\'
        #允许的域名
        # allowed_domains = [\'www.baidu.com\']
        #起始的url列表:列表中存放的url会被scrapy自动的进行请求发送
        start_urls = [\'https://www.baidu.com/\',\'https://www.sogou.com/\']
        #用作于数据解析:将start_urls列表中对应的url请求成功后的响应数据进行解析
        def parse(self, response):
            print(response.text) #获取字符串类型的响应内容
            print(response.body)#获取字节类型的相应内容
    View Code
  • 设置修改settings.py配置文件相关配置

    # settings.py 文件中
        #不遵从robots协议
        #进行UA伪装
        #进行日志等级设定: LOG_LEVEL = False
    View Code

    setting.py中 ----- 基于终端指令的持久化存储操作

    BOT_NAME = \'firstBlood\'
    
    SPIDER_MODULES = [\'firstBlood.spiders\']
    NEWSPIDER_MODULE = \'firstBlood.spiders\'
    
    
    # Crawl responsibly by identifying yourself (and your website) on the user-agent
    USER_AGENT = \'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36\'       #进行ua伪装
    # Obey robots.txt rules
    ROBOTSTXT_OBEY = False    #不遵从robotstx协议
    LOG_LEVEL = \'ERROR\'       #输出错误类型的日志
    View Code

    setting.py ------------- 基于管道的持久化存储

    BOT_NAME = \'qiubaiPro\'
    USER_AGENT = \'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36\'
    
    SPIDER_MODULES = [\'qiubaiPro.spiders\']
    NEWSPIDER_MODULE = \'qiubaiPro.spiders\'
    
    
    ITEM_PIPELINES = {
       \'qiubaiPro.pipelines.QiubaiproPipeline\': 300, #300表示的是优先级(数值越小优先级越大)
    }
    View Code
  • 执行爬虫程序:scripy crawl spiderName

    • 不输出日志(错误信息会在日志中输出,不要使用) 

      scripy crawl spiderName --nolog
      View Code

7.2.3scrapy框架持久化存储

#持久化存储
    #基于终端指令
        特性 : 只能将 parse 方法的返回值存储到本地的磁盘文件中
        指令 : scripy crawl spiderName -o filepath
    #基于管道
        #实现流程
        1.数据解析
        2.在item类中定义相关属性
        3.将解析的数据封装到一个 item 对象中(item文件中对应类的对象)
        4.向管道提交item
        5.在管道文件中的 process_item 方法中接收 item 进行持久化存储
        6.在配置文件中开启管道
    
    #管道中需注意细节:
        1.配置文件中开启的管道是一个字典,字典中的键值表示的就是某一个管道
        2.在管道对应的源文件中其实可以定义多个管道类,一种形式的持久化存储
        3.在process_item方法中的 return item 表示的是提交给下一个即将被执行的管道类
        4.爬虫文件中yield item 只可以将item传递给第一个被执行的(优先级最高的)管道
    
    #将同一份数据持久化存储到不同平台中:
        #分析
        1.管道文件中的一个管道内负责数据的一种形式的持久化存储

setting.py中 ----- 基于终端指令的持久化存储操作

BOT_NAME = \'firstBlood\'

SPIDER_MODULES = [\'firstBlood.spiders\']
NEWSPIDER_MODULE = \'firstBlood.spiders\'


# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = \'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36\'       #进行ua伪装
# Obey robots.txt rules
ROBOTSTXT_OBEY = False    #不遵从robotstx协议
LOG_LEVEL = \'ERROR\'       #输出错误类型的日志
View Code

setting.py ------------- 基于管道的持久化存储

BOT_NAME = \'qiubaiPro\'
USER_AGENT = \'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36\'

SPIDER_MODULES = [\'qiubaiPro.spiders\']
NEWSPIDER_MODULE = \'qiubaiPro.spiders\'


ITEM_PIPELINES = {
   \'qiubaiPro.pipelines.QiubaiproPipeline\': 300, #300表示的是优先级(数值越小优先级越大)
}
View Code

糗事百科

qiubai.py

import scrapy
from qiubaiPro.items import QiubaiproItem

class QiubaiSpider(scrapy.Spider):
    name = \'qiubai\'
    # allowed_domains = [\'www.xxx.com\']
    start_urls = [\'https://www.qiushibaike.com/text/\']
    
    #基于终端指令的持久化存储操作
    # def parse(self, response):
    #     div_list = response.xpath(\'//*[@id="content-left"]/div\')
    #     all_data = []
    #     for div in div_list:
    #         #scrapy中的xpath返回的列表的列表元素一定是Selector对象,我们最终想要的解析的
    #         #数据一定是存储在该对象中
    #         #extract()将Selector对象中data参数的值取出
    #         # author = div.xpath(\'./div[1]/a[2]/h2/text()\')[0].extract()
    #         author = div.xpath(\'./div[1]/a[2]/h2/text()\').extract_first()
    #         #列表直接调用extract表示的是将extract作用到每一个列表元素中
    #         content = div.xpath(\'./a[1]/div/span//text()\').extract()
    #         content = \'\'.join(content)
    #         dic = {
    #             \'author\':author,
    #             \'content\':content
    #         }
    #         all_data.append(dic)
    #     return all_data
    
   
    #基于管道的持久化存储
    def parse(self, response):
        div_list = response.xpath(\'//*[@id="content-left"]/div\')
        all_data = []
        for div in div_list:
            #scrapy中的xpath返回的列表的列表元素一定是Selector对象,我们最终想要的解析的
            #数据一定是存储在该对象中
            #extract()将Selector对象中data参数的值取出
            # author = div.xpath(\'./div[1]/a[2]/h2/text()\')[0].extract()
            author = div.xpath(\'./div[1]/a[2]/h2/text()\').extract_first()
            #列表直接调用extract表示的是将extract作用到每一个列表元素中
            content = div.xpath(\'./a[1]/div/span//text()\').extract()
            content = \'\'.join(content)

            #将解析的数据存储到item对象
            item = QiubaiproItem()
            item[\'author\'] = author
            item[\'content\'] = content

            #将item提交给管道
            yield item #item一定是提交给了优先级最高的管道类
View Code

itims.py

import scrapy

class QiubaiproItem(scrapy.Item):
    # define the fields for your item here like:
    author = scrapy.Field() #Field可以将其理解成是一个万能的数据类型
    content = scrapy.Field()
View Code

pipelines.py 管道文件

import pymysql
from redis import Redis
class QiubaiproPipeline(object):
    fp = None
    def open_spider(self,spider):
        print(\'开始爬虫......\')
        self.fp = open(\'qiushibaike.txt\',\'w\',encoding=\'utf-8\')

    #使用来接收爬虫文件提交过来的item,然后将其进行任意形式的持久化存储
    #参数item:就是接收到的item对象
    #该方法每接收一个item就会调用一次
    def process_item(self, item, spider):
        author = item[\'author\']
        content= item[\'content\']

        self.fp.write(author+\':\'+content+\'\\n\')
        return item #item是返回给了下一个即将被执行的管道类

    def close_spider(self,spider):
        print(\'结束爬虫!\')
        self.fp.close()

        
#负责将数据存储到mysql
class MysqlPL(object):
    conn = None
    cursor = None
    def open_spider(self,spider):
        self.conn = pymysql.Connect(host=\'127.0.0.1\',port=3306,user=\'root\',password=\'123\',db=\'spider\',charset=\'utf8\')
        print(self.conn)
    def process_item(self,item,spider):
        author = item[\'author\']
        content = item[\'content\']

        sql = \'insert into qiubai values ("%s","%s")\'%(author,content)
        self.cursor = self.conn.cursor()
        try:
            self.cursor.execute(sql)
            self.conn.commit()
        except Exception as e:
            print(e)
            self.conn.rollback()
        return item
    
    def close_spider(self,spider):
        self.cursor.close()
        self.conn.close()

#基于redis的管道存储
class RedisPL(object):
    conn = None
    def open_spider(self,spider):
        self.conn = Redis(host=\'127.0.0.1\',port=6379)
        print(self.conn)
        
    def process_item(self,item,spider):
        self.conn.lpush(\'all_data\',item)     # name  value
        #注意:如果将字典写入redis报错:pip install -U redis==2.10.6
View Code

7.2.4scrapy框架之递归解析和post请求

递归解析(手动请求发送)

  • 使用场景 :爬取多个页码对应的页面源码数据

  • yield scrapy.Request(url,callback)

import scrapy
from qiubaiPro.items import QiubaiproItem

class QiubaiSpider(scrapy.Spider):
    name = \'qiubai\'
    # allowed_domains = [\'www.xxx.com\']
    start_urls = [\'https://www.qiushibaike.com/text/\']

    #将多个页码对应的页面数据进行爬取和解析的操作
    url = \'https://www.qiushibaike.com/text/page/%d/\'#通用的url模板
    pageNum = 1
    #parse第一次调用表示的是用来解析第一页对应页面中的段子内容和作者
    def parse(self, response):
        div_list = response.xpath(\'//*[@id="content-left"]/div\')
        all_data = []
        for div in div_list:
            # scrapy中的xpath返回的列表的列表元素一定是Selector对象,我们最终想要的解析的
            # 数据一定是存储在该对象中
            # extract()将Selector对象中data参数的值取出
            # author = div.xpath(\'./div[1]/a[2]/h2/text()\')[0].extract()
            author = div.xpath(\'./div[1]/a[2]/h2/text()\').extract_first()
            # 列表直接调用extract表示的是将extract作用到每一个列表元素中
            content = div.xpath(\'./a[1]/div/span//text()\').extract()
            content = \'\'.join(content)

            # 将解析的数据存储到item对象
            item = QiubaiproItem()
            item[\'author\'] = author
            item[\'content\'] = content

            # 将item提交给管道
            yield item  # item一定是提交给了优先级最高的管道类

        if self.pageNum <= 5:
            self.pageNum += 1
            new_url = format(self.url%self.pageNum)
            #手动请求(get)的发送
            yield scrapy.Request(new_url,callback=self.parse)
View Code

post请求发送

  • 问题:在之前代码中,我们从来没有手动的对start_urls列表中存储的起始url进行过请求的发送,但是起始url的确是进行了请求的发送,那这是如何实现的呢?

    • 解答:其实是因为爬虫文件中的爬虫类继承到了Spider父类中的start_requests(self)这个方法,该方法就可以对start_urls列表中的url发起请求:

        def start_requests(self):
              for u in self.start_urls:
                 yield scrapy.Request(url=u,callback=self.parse)
  • 【注意】该方法默认的实现,是对起始的url发起get请求,如果想发起post请求,则需要子类重写该方法。

    • 方法: 重写start_requests方法,让其发起post请求:

      def start_requests(self):
              #请求的url
              post_url = \'http://fanyi.baidu.com/sug\'
              # post请求参数
              formdata = {
                  \'kw\': \'wolf\',
              }
              # 发送post请求
              yield scrapy.FormRequest(url=post_url, formdata=formdata, callback=self.parse)
    
    

scrapy五大核心组件

#引擎(Scrapy)
  用来处理整个系统的数据流处理, 触发事务(框架核心)
#调度器(Scheduler)
  用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址
#下载器(Downloader)
  用于下载网页内容, 并将网页内容返回给蜘蛛(Scrapy下载器是建立在twisted这个高效的异步模型上的)
#爬虫(Spiders)
  爬虫是主要干活的, 用于从特定的网页中提取自己需要的信息, 即所谓的实体(Item)。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面
#项目管道(Pipeline)
  负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据。

 

  • 工作流程

    #步骤
    1.spider中的url被封装成请求对象交给引擎(每一个url对应一个请求对象);
    2.引擎拿到请求对象之后, 将其全部交给调度器;
    3.调度器拿到所有请求对象后, 通过内部的过滤器过滤掉重复的url, 最后将去重后的所有url对应的请求对象压入到队列中, 随后调度器调度出其中一个请求对象, 并将其交给引擎;
    4.引擎将调度器调度出的请求对象交给下载器;
    5.下载器拿到该请求对象去互联网中下载数据;
    6.数据下载成功后会被封装到response中, 随后response会被交给下载器;
    7.下载器将response交给引擎;
    8.引擎将response交给spiders;
    9.spiders拿到response后调用回调方法进行数据解析, 解析成功后产生item, 随后spiders将item交给引擎;
    10.引擎将item交给管道, 管道拿到item后进行数据的持久化存储.

7.3基于scrapy进行图片数据的爬取