zoukankan      html  css  js  c++  java
  • Python日记:基于Scrapy的爬虫实现

    安装 pywin32 和python版本一致 

    地址 https://sourceforge.net/projects/pywin32/files/pywin32/Build%20221/
    安装过程中提示找不到Python2.7
    解决方法:http://blog.csdn.net/pppii/article/details/48679403

    安装Scrapy 使用pip

    1、使用命令行创建爬虫项目
    scrapy startproject myspider # cmd进入指定文件夹后创建一个名为 myspider的爬虫

    2、启动pyCharm
    打开项目 myspider ,在文件夹spiders下创建MySprider.py文件
    添加我的爬虫 class Channel9Spider(scrapy.Spider):
    name 表示爬虫的名称 属于唯一属性
    allowed_domins=[] 爬虫允许的域
    start_urls=[] 爬虫开始的页面
    def parse(self,response): 访问地址后调用的方法
    def details_parse(self,response): 处理详情页面的方法

    MySprider.py遇到的问题:
    1、windows命令提示符中打印爬取的文件名报错
    原因:是命令行字符集和网页字符集不一致
    处理方法:print item["title"].encode("gbk","ignore")
    2、回调方法报错
    原因:PyScrapy默认给回调加了个括号
    处理方法:去掉回调方法后的括号,需要传参使用Request(url=.. , meta={'name':'yancl',....},calback=self.details_parse,dont_filter=True)
    3、提示访问被拒绝
    原因:1、robots 协议问题 2、由于设置了允许爬取的域
    处理方法:1、修改settings.py 设置ROBOTSTXT_OBEY = True
    2、调用Request方法设置dont_filter=True

    打开 items.py
    添加在处理页面后要传递给pipeline的item数据对象
    用到了下载所以添加 file_urls,files,file_paths

    打开 pipeline.py
    1、添加一个继承FilesPipeline文件下载管道的实现方法 MyFilesPipeline
    2、添加一个记录文件方法 JsonWithEncodingPipeline

    打开settings.py
    1、启用我的Item Pipeline组建。我打算下载一个视频就记录一条对应的Json信息
    2、添加视频下载保存文件的路径


    再次启动爬虫 scrapy crawl myspider
    遇到的问题:
    1、下载文件过大
    2、连接超时
    3、文件下载的路径问题,默认添加full的文件夹
    4、文件名问题

    对于问题1、2、3 修改settings
    DOWNLOAD_MAXSIZE = 325674803 #字节
    DOWNLOAD_WARNSIZE = 325674803 #字节
    DOWNLOAD_TIMEOUT = 30 * 60 #单位秒
    FILES_STORE = "F:\mp4files" #直接使用绝对路径
    对于问题3,修改MyFilesPipeline方法 重写file_path方法

    再次启动爬虫运行正常,但是还有2个小问题,1、有一个文件自动添加了文件夹 2、有几个文件没有后缀大小为0KB
    根据日志分析是文件名导致了 文件名中不能有:/ 等特殊字符

    MySpider.py

    import scrapy
    from mydemo.items import MydemoItem
    from scrapy.http import Request
    from scrapy.selector import Selector
    
    download_domain = "https://channel9.msdn.com"
    class Channel9Spider(scrapy.Spider):
        name = "myspider"
        allowed_domains = [".msdn.com"]
        start_urls = [
            "https://channel9.msdn.com/Events/Ignite/Microsoft-Ignite-China-2016?sort=status&direction=desc"
        ]
    
        def parse(self,response):
            sale = Selector(response)
            for a in sale.xpath("//h3"):
                title = a.xpath("a/text()").extract()[0]
                line = a.xpath("a/@href").extract()[0]
                fileurl = download_domain + line
                yield Request(url=fileurl,meta={'title':title},callback=self.details_parse,dont_filter=True)
    
            next_page = sale.xpath("//a[@rel='next']/@href").extract()
            if next_page:
                pagepath =  download_domain+next_page[0]
                yield Request(url=pagepath,callback=self.parse,dont_filter=True)
    
        def details_parse(self,response):
            sale = Selector(response)
            item = MydemoItem()
            item["title"] = response.meta['title']
            fileurl = sale.xpath("//*[@id='format']/option/@value").extract()[0]
            item["file_urls"] = [fileurl]
            yield item
    

    items.py

    class MydemoItem(scrapy.Item):
        # define the fields for your item here like:
        # name = scrapy.Field()
        title = scrapy.Field()
        link = scrapy.Field()
        content = scrapy.Field()
    
        file_urls = scrapy.Field()
        files = scrapy.Field()
        file_paths = scrapy.Field()
        pass
    

    pipelines.py

    # -*- coding: utf-8 -*-
    
    # Define your item pipelines here
    #
    # Don't forget to add your pipeline to the ITEM_PIPELINES setting
    # See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
    import scrapy
    import codecs
    import json
    import time
    from scrapy.pipelines.files import FilesPipeline
    from scrapy.exceptions import DropItem
    
    class MydemoPipeline(object):
        def process_item(self, item, spider):
            return item
    
    class JsonWithEncodingPipeline(object):
        def __init__(self):
            self.file = codecs.open('file.json','w',encoding='utf-8')
    
        def process_item(self,item,spider):
            timeSatamp = time.time()
            timeTuple = time.localtime(timeSatamp)
            curTime = time.strftime("%Y-%m-%d %H:%M:%S",timeTuple)
            line = "["+curTime+"] "+json.dumps(dict(item),ensure_ascii=False)+"
    "
            self.file.write(line)
            return item
    
        def spider_closed(self,spider):
            self.file.close()
    
    
    class MyFilesPipeline(FilesPipeline):
        def get_media_requests(self,item,info):
            for file_url in item['file_urls']:
                yield scrapy.Request(file_url,meta={'title':item['title']})
    
        def item_completed(self, results, item, info):
            file_paths = [x['path'] for ok, x in results if ok]
            if not file_paths:
                raise DropItem("Item contains no Files")
            item["file_paths"] = file_paths
            return item
    
        def file_path(self,request,response=None,info=None):
            title = request.meta['title']
            file_guid = title + '.'+request.url.split('/')[-1].split('.')[-1]
            filename = u'{0}'.format(file_guid)
            return filename
    

    settings.py 

    生成的日志截图如下:

    爬取的文件截图:

      

     



  • 相关阅读:
    Parameter Binding in ASP.NET Web API
    Which HTTP methods match up to which CRUD methods?
    ErrorHandling in asp.net web api
    HttpStatusCode
    Autofac Getting Started(默认的构造函数注入)
    Autofac Controlling Scope and Lifetime
    luvit 被忽视的lua 高性能框架(仿nodejs)
    undefined与null的区别
    VsCode中使用Emmet神器快速编写HTML代码
    字符串匹配---KMP算法
  • 原文地址:https://www.cnblogs.com/dbycl/p/6757910.html
Copyright © 2011-2022 走看看