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 

生成的日志截图如下:

爬取的文件截图:

  

 



原文地址:https://www.cnblogs.com/dbycl/p/6757910.html