• python爬虫框架(2)--PySpider框架安装配置


    1.安装

     1.phantomjs

    PhantomJS 是一个基于 WebKit 的服务器端 JavaScript API。它全面支持web而不需浏览器支持,其快速、原生支持各种Web标准:DOM 处理、CSS 选择器、JSON、Canvas 和 SVG。 PhantomJS 可以用于页面自动化、网络监测、网页截屏以及无界面测试等。

    http://phantomjs.org/download.html

    2.pyspider

    直接利用 pip 安装即可

    pip install pyspider

    测试

    如果安装过程没有提示任何错误,那就证明一些OK。

    命令行输入

    pyspider all

    然后浏览器访问 http://localhost:5000

    观察一下效果,如果可以正常出现 PySpider 的页面,那证明一切OK

    3.配置环境变量

    将PhantomJS放到C:Python27Scripts中,并将可执行程序文件所在位置以及C:Python27Scripts添加到环境变量的Path中

    2.PySpider的用法

    官方文档:http://docs.pyspider.org/en/latest/

    1)首先在scripts文件夹下打开cmd,输入:

    pyspider all

    这句命令的意思是,运行 pyspider 并 启动它的所有组件,包括PhantomJS

    2)接下来在浏览器中输入 http://localhost:5000,可以看到 PySpider 的主界面,点击右下角的 Create,命名为 taobaomm,当然名称你以随意取,继续点击 Create。

    整个页面分为两栏,左边是爬取页面预览区域,右边是代码编写区域。下面对区块进行说明:

    左侧绿色区域:这个请求对应的 JSON 变量,在 PySpider 中,其实每个请求都有与之对应的 JSON 变量,包括回调函数,方法名,请求链接,请求数据等等。

    绿色区域右上角Run:点击右上角的 run 按钮,就会执行这个请求,可以在左边的白色区域出现请求的结果。

    左侧 enable css selector helper: 抓取页面之后,点击此按钮,可以方便地获取页面中某个元素的 CSS 选择器。

    左侧 web: 即抓取的页面的实时预览图。

    左侧 html: 抓取页面的 HTML 代码。

    左侧 follows: 如果当前抓取方法中又新建了爬取请求,那么接下来的请求就会出现在 follows 里。

    左侧 messages: 爬取过程中输出的一些信息。

    右侧代码区域: 你可以在右侧区域书写代码,并点击右上角的 Save 按钮保存。

    右侧 WebDAV Mode: 打开调试模式,左侧最大化,便于观察调试。

    3)开始爬取

    https://mm.taobao.com/json/request_top_list.htm?page=1,其中 page 参数代表页码。所以我们暂时抓取前 30 页。页码到最后可以随意调整。

    首先定义基地址,然后定义爬取的页码和总页码。

    from pyspider.libs.base_handler import *
    
    
    class Handler(BaseHandler):
        crawl_config = {
        }
        
        def __init__(self):
            self.baseurl = 'https://mm.taobao.com/json/request_top_list.htm?page='
            self.page_num = 1
            self.total_num = 30
    
        @every(minutes=24 * 60)
        def on_start(self):
            while self.page_num <= self.total_num:
                url = self.baseurl + str(self.page_num)
                print url
                self.crawl(url, callback=self.index_page, validate_cert=False)
                self.page_num += 1
    
        @config(age=10 * 24 * 60 * 60)
        def index_page(self, response):
            for each in response.doc('a[href^="http"]').items():
                self.crawl(each.attr.href, callback=self.detail_page, validate_cert=False)
    
        @config(priority=2)
        def detail_page(self, response):
            return {
                "url": response.url,
                "title": response.doc('title').text(),
            }

    点击 save 保存代码,然后点击左边的 run,运行代码。

    运行后会发现 follows 出现了 30 这个数字,说明我们接下来有 30 个新请求,点击可查看所有爬取列表。另外控制台也有输出,将所有要爬取的 URL 打印了出来。

    然后点击左侧任意一个绿色箭头,可以继续爬取这个页面。例如点击第一个 URL,来爬取这个 URL

    4)HTTP 599: SSL certificate problem错误的解决方法

    在 crawl 方法中加入忽略证书验证的参数,validate_cert=False

    5)修改 index_page 方法

        def index_page(self, response):
            for each in response.doc('a[href^="http"]').items():
                self.crawl(each.attr.href, callback=self.detail_page, validate_cert=False)

    其中 response 就是刚才爬取的列表页,response 其实就相当于列表页的 html 代码,利用 doc 函数,其实是调用了 PyQuery,用 CSS 选择器得到每一个MM的链接,然后重新发起新的请求。

     比如,这里拿到的 each.attr.href 可能是 mm.taobao.com/self/model_card.htm?user_id=687471686,在这里继续调用了 crawl 方法,代表继续抓取这个链接的详情。

    然后回调函数就是 detail_page,爬取的结果会作为 response 变量传过去。detail_page 接到这个变量继续下面的分析。

    右边的页面使用 JS 渲染生成的,而普通的抓取是不能得到 JS 渲染后的页面的,PySpider 提供了动态解析 JS 的机制。因为在前面装好了 PhantomJS,所以,这时候就轮到它来出场了。在最开始运行 PySpider 的时候,使用了pyspider all命令,这个命令是把 PySpider 所有的组件启动起来,其中也包括 PhantomJS。

    只是简单地加了一个 fetch_type='js',点击绿色的返回箭头,重新运行一下。

    6)数据分析

    继续修改 detail_page 方法,然后增加一个 domain_page 方法,用来处理每个 MM 的个性域名。

    先点击F12打开开发者选项,找到mm的个性域名模块

    .mm-p-domain-info li > span指的是从域名地点的div标签到span标签的路径上的所有祖先节点。再加上”https:”就构成了个性域名的URL。之后利用self.crawl来继续对domain这个页面进行爬取。(CSS选择器详见python爬虫(7)--Beautiful Soup的用法

        def detail_page(self, response):
            domain = 'https:' + response.doc('.mm-p-domain-info li > span').text()
            print domain
            self.crawl(domain, callback=self.domain_page)
            
        def domain_page(self,response):
            pass

    继续重新 run,预览一下页面,看到了 MM 的所有图片。

    7)保存

    完善 domain_page 代码,实现保存简介和遍历保存图片的方法。

    在这里,PySpider 有一个特点,所有的 request 都会保存到一个队列中,并具有去重和自动重试机制。所以,最好的解决方法是,把每张图片的请求都写成一个 request,然后成功后用文件写入即可,这样会避免图片加载不全的问题。

    import os
    
    class Deal:
        def __init__(self):
            self.path = DIR_PATH
            if not self.path.endswith('/'):
                self.path = self.path + '/'
            if not os.path.exists(self.path):
                os.makedirs(self.path)
                
        def mkDir(self, path):
            path = path.strip()
            dir_path = self.path + path
            exists = os.path.exists(dir_path)
            if not exists:
                os.makedirs(dir_path)
                return dir_path
            else:
                return dir_path
            
        def saveImg(self, content, path):
            f = open(path, 'wb')
            f.write(content)
            f.close
            
        def saveBrief(self, content, dir_path, name):
            file_name = dir_path + "/" + name + ".txt"
            f = open(file_name, "w+")
            f.write(content.encode('utf-8'))
            
        def getExtension(self, url):
            extension = url.split('.')[-1]
            return extension

    这里面包含了四个方法。

    mkDir:创建文件夹,用来创建 MM 名字对应的文件夹。

    saveBrief: 保存简介,保存 MM 的文字简介。

    saveImg: 传入图片二进制流以及保存路径,存储图片。

    getExtension: 获得链接的后缀名,通过图片 URL 获得。

    然后在 domain_page 中具体实现如下

        def domain_page(self,response):
            name = response.doc('.mm-p-model-info-left-top dd > a').text()
            dir_path = self.deal.mkDir(name)
            brief = response.doc('.mm-aixiu-content').text()
            if dir_path:
                imgs = response.doc('.mm-aixiu-content img').items()
                count = 1
                self.deal.saveBrief(brief, dir_path, name)
                for img in imgs:
                    url = img.attr.src
                    if url:
                        extension = self.deal.getExtension(url)
                        file_name = name + str(count) + '.' + extension
                        count += 1
                        self.crawl(img.attr.src, callback=self.save_img, save={'dir_path':dir_path, 'file_name':file_name}, validate_cert=False)
                        
        def save_img(self, response):
            content = response.content
            dir_path = response.save['dir_path']
            file_name = response.save['file_name']
            file_path = dir_path + '/' + file_name
            self.deal.saveImg(content, file_path)

    以上方法首先获取了页面的所有文字,然后调用了 saveBrief 方法存储简介。

    然后遍历了 MM 所有的图片,并通过链接获取后缀名,和 MM 的姓名以及自增计数组合成一个新的文件名,调用 saveImg 方法保存图片。

    完善代码如下:

    #!/usr/bin/env python
    # -*- encoding: utf-8 -*-
    # Created on 2018-01-24 17:33:28
    # Project: taobaomm
    
    from pyspider.libs.base_handler import *
    
    DIR_PATH = '/var/py/mm'
    
    class Handler(BaseHandler):
        crawl_config = {
        }
        
        def __init__(self):
            self.baseurl = 'https://mm.taobao.com/json/request_top_list.htm?page='
            self.page_num = 1
            self.total_num = 30
            self.deal = Deal()
    
        @every(minutes=24 * 60)
        def on_start(self):
            while self.page_num <= self.total_num:
                url = self.baseurl + str(self.page_num)
                print url
                self.crawl(url, callback=self.index_page, validate_cert=False)
                self.page_num += 1
    
        @config(age=10 * 24 * 60 * 60)
        def index_page(self, response):
            for each in response.doc('a[href^="http"]').items():
                self.crawl(each.attr.href, callback=self.detail_page, fetch_type='js', validate_cert=False)
    
        @config(priority=2)
        def detail_page(self, response):
            domain = 'https:' + response.doc('.mm-p-domain-info li > span').text()
            print domain
            self.crawl(domain, callback=self.domain_page, validate_cert=False)
            
        def domain_page(self,response):
            name = response.doc('.mm-p-model-info-left-top dd > a').text()
            dir_path = self.deal.mkDir(name)
            brief = response.doc('.mm-aixiu-content').text()
            if dir_path:
                imgs = response.doc('.mm-aixiu-content img').items()
                count = 1
                self.deal.saveBrief(brief, dir_path, name)
                for img in imgs:
                    url = img.attr.src
                    if url:
                        extension = self.deal.getExtension(url)
                        file_name = name + str(count) + '.' + extension
                        count += 1
                        self.crawl(img.attr.src, callback=self.save_img, save={'dir_path':dir_path, 'file_name':file_name}, validate_cert=False)
                        
        def save_img(self, response):
            content = response.content
            dir_path = response.save['dir_path']
            file_name = response.save['file_name']
            file_path = dir_path + '/' + file_name
            self.deal.saveImg(content, file_path)
            
    import os
    
    class Deal:
        def __init__(self):
            self.path = DIR_PATH
            if not self.path.endswith('/'):
                self.path = self.path + '/'
            if not os.path.exists(self.path):
                os.makedirs(self.path)
                
        def mkDir(self, path):
            path = path.strip()
            dir_path = self.path + path
            exists = os.path.exists(dir_path)
            if not exists:
                os.makedirs(dir_path)
                return dir_path
            else:
                return dir_path
            
        def saveImg(self, content, path):
            f = open(path, 'wb')
            f.write(content)
            f.close
            
        def saveBrief(self, content, dir_path, name):
            file_name = dir_path + "/" + name + ".txt"
            f = open(file_name, "w+")
            f.write(content.encode('utf-8'))
            
        def getExtension(self, url):
            extension = url.split('.')[-1]
            return extension
  • 相关阅读:
    一些要学习的文章
    Android 应用检查更新并下载
    Android中如何下载文件并显示下载进度
    android IntentService和ResultReceiver的异步处理
    android 优秀图表库之MPAndroidChart
    android 仿QQ气泡聊天界面
    android canvas中rotate()和translate()两个方法详解
    android 透明弹出搜索框
    【转】ANDROID自定义视图——onLayout源码 流程 思路详解
    【转】ANDROID自定义视图——onMeasure,MeasureSpec源码 流程 思路详解
  • 原文地址:https://www.cnblogs.com/lzhc/p/8343246.html
Copyright © 2020-2023  润新知