爬虫: Scrapy proxy HttpProxyMiddleware

 

  1. HttpProxyMiddleware 的使用
  2. setting.py
    1. USER_AGENT_LIST = [
      'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.36 Safari/535.7',
      'Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:16.0) Gecko/16.0 Firefox/16.0',
      'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/534.55.3 (KHTML, like Gecko) Version/5.1.3 Safari/534.53.10'
      ]
      HTTP_PROXY = 'http://127.0.0.1:8888'
      DOWNLOADER_MIDDLEWARES = {
      'tutorial.middlewares.RandomUserAgentMiddleware': 400,
      'tutorial.middlewares.ProxyMiddleware': 410,
      'scrapy.contrib.downloadermiddleware.useragent.UserAgentMiddleware': None
      # Disable compression middleware, so the actual HTML pages are cached
      }

 

3.   middleware.py

import os
import random
from scrapy.conf import settings


class RandomUserAgentMiddleware(object):
def process_request(self, request, spider):
ua = random.choice(settings.get('USER_AGENT_LIST'))
if ua:
request.headers.setdefault('User-Agent', ua)

class ProxyMiddleware(object):
def process_request(self, request, spider):
request.meta['proxy'] = settings.get('HTTP_PROXY')

4. 代理设为 HTTP_PROXY = 'http://127.0.0.1:8888' , 通过charles
对爬虫进行抓包,查看请求的情况




 

参考:

[1]http://www.php101.cn/2015/03/27/Scrapy%E4%B9%8B%E6%97%85(1)%E4%BD%BF%E7%94%A8http_proxy/

[2]http://pkmishra.github.io/blog/2013/03/18/how-to-run-scrapy-with-TOR-and-multiple-browser-agents-part-1-mac/    [详细,简单]

[3]http://www.kuaidaili.com/free/inha/   [免费代理池]

[4]https://husless.github.io/2015/07/01/using-scrapy-with-proxies/  

[5]http://www.cnblogs.com/rwxwsblog/p/4575894.html

charles : 抓去https 出现问题 ,v2ex模拟登录

  1.  v2ex 模拟登录工具不能使用了,由于站长将登陆规则改了,
  2. 打算重新写个,使用charles对v2ex进行抓包,出现错误
  3. pc端的证书有点问题
  4. mac 打开 keychain Access ,重新信任 charles 证书 
  5. 重启chrome
  6. 重启电脑
  7. 搞定
  8. 用scrapy 重新写了v2ex模拟登录,每日获取金币

 

 

参考:

[1]https://segmentfault.com/q/1010000005625874

爬虫: 去重 [TODO]

1.

在scrapy的进程中,默认的方式是把url放到内存中,从而到达过滤到重复的url情况。如果是在不同的进程中,可以开启RFPDupeFilter,也可以自定义DupeFilte

 

利用scrapy-redis 可以自动出去重复的url

 

scrapy 默认会根据url的finger print 进行去重的,不要担心请求发重复了

 

参考:

[1]http://www.fengxiaochuang.com/?p=144 [TODO]

爬虫 : 分布式爬虫搭建 [TODO]

  1. scrapy-redis

2.

作者:杨恒
链接:https://www.zhihu.com/question/32302268/answer/55724369
来源:知乎
著作权归作者所有,转载请联系作者获得授权。

一时兴起写了篇回复,能给大家解决一点小问题,十分高兴。但偶尔被误认为是大牛,诚惶诚恐。
只是当初一点小爱好而已,大牛实在是不敢当。

另外要对私信给我请求帮助的朋友说声抱歉,我已经离开技术岗位很长时间了,手头上早已没有了编程的环境,加上目前工作太多,对大家的问题也是有心无力(我这人太怂,也不敢给大家随便丢个回复)。

最后祝大家学习爬虫的路上一帆风顺~(虽然不大可能,不过加油吧)

以下是正文
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
不妖自来~
我刚刚接触scrapy的时候,也看过这个项目,奈何对scrapy本身就不怎么熟悉,所以当时怎么也想不明白,直到后来开始看scrapy 的源代码,才渐渐明白。这里提一下我的看法,水平有限,不敢保证完全正确,欢迎指正。

一、scrapy和scrapy-redis的主要区别在哪里?
个人认为,scrapy和scrapy-redis不应该讨论区别。

scrapy 是一个通用的爬虫框架,其功能比较完善,可以帮你迅速的写一个简单爬虫,并且跑起来。scrapy-redis是为了更方便地实现scrapy分布式爬取,而提供了一些以redis为基础的组件(注意,scrapy-redis只是一些组件,而不是一个完整的框架)。你可以这么认为,scrapy是一工厂,能够出产你要的spider。而scrapy-redis是其他厂商为了帮助scrapy工厂更好的实现某些功能而制造了一些设备,用于替换scrapy工厂的原设备。
所以要想跑分布式,先让scrapy工厂搭建起来,再用scrapy-redis设备去更换scrapy的某些设备。

那么这些scrapy-redis组件有什么突出特点呢?他们使用了redis数据库来替换scrapy原本使用的队列结构(deque),换了数据结构,那么相应的操作当然都要换啦,所以与队列相关的这些组件都做了更换。

二、scrapy-redis提供了哪些组件?
Scheduler、Dupefilter、Pipeline、Spider
提供了哪些组件具体见darkrho/scrapy-redis · GitHub

三、为什么要提供这些组件?
这要从哪哪哪说起(喝口水,默默地望着远方……)

我们先从scrapy的“待爬队列”和“Scheduler”入手:
咱们玩过爬虫(什么玩过,是学习过,研究过,爱过也被虐过)的同学都多多少少有些了解,在爬虫爬取过程当中,有一个主要的数据结构是“待爬队列”,以及能够操作这个队列的调度器(也就是Scheduler啦)。scrapy官方文档对这二者的描述不多,基本上没提。

scrapy使用什么样的数据结构来存放待爬取的request呢?
其实没用高大上的数据结构,就是python自带的collection.deque,不过当然是改造过后的啦(后面所说到的deque均是指scrapy改造之后的队列,至于如何改造的,就去看代码吧)。
详见源代码queuelib/queue.py at master · scrapy/queuelib · GitHub
不过咱们用一用deque就会意识到,该怎么让两个以上的Spider共用这个deque呢?答案是,我水平不够,不知道。那分布式怎么实现呢,待爬队列都不能共享,还玩个泥巴呀。scrapy-redis提供了一个解决方法,把deque换成redis数据库,我们从同一个redis服务器存放要爬取的request,这样就能让多个spider去同一个数据库里读取,这样分布式的主要问题就解决了嘛。

—————————————————分割线的随地大小便———————————————————-
那么问题又来了,我们换了redis来存放队列,哪scrapy就能直接分布式了么?(当初天真的我呀~
当然不能。我们接着往下说。scrapy中跟“待爬队列”直接相关的就是调度器“Scheduler”:scrapy/scheduler.py at master · scrapy/scrapy · GitHub,它负责对新的request进行入列操作(加入deque),取出下一个要爬取的request(从deque中取出)等操作。
在scrapy中,Scheduler并不是直接就把deque拿来就粗暴的使用了,而且提供了一个比较高级的组织方法,它把待爬队列按照优先级建立了一个字典结构,比如:
{
priority0:队列0
priority1:队列2
priority2:队列2
}
然后根据request中的priority属性,来决定该入哪个队列。而出列时,则按priority较小的优先出列。为了管理这个比较高级的队列字典,Scheduler需要提供一系列的方法。说这么多有什么意义呢?最主要的指导意义就是:你要是换了redis做队列,这个scrapy下的Scheduler就用不了,所以自己写一个吧。

于是就出现了scrapy-redis的专用scheduler:scrapy-redis/scheduler.py at master · darkrho/scrapy-redis · GitHub,其实可以对比一下看,操作什么的都差不太多。主要是操作的数据结构变了。

———————————————-被当众抓住的分割线———————————————————
那么既然使用了redis做主要数据结构,能不能把其他使用自带数据结构关键功能模块也换掉呢?(关键部分使用自带数据结构简直有种没穿小内内的危机感,这是本人的想法~)
在我们爬取过程当中,还有一个重要的功能模块,就是request去重(已经发送过得请求就别再发啦,也要考虑一下服务器君的感受好伐)。

scrapy中是如何实现这个去重功能的呢?用集合~
scrapy中把已经发送的request指纹放入到一个集合中,把下一个request的指纹拿到集合中比对,如果该指纹存在于集合中,说明这个request发送过了,如果没有则继续操作。这个核心的判重功能是这样实现的:

def request_seen(self, request):
    #self.figerprints就是一个指纹集合
    fp = self.request_fingerprint(request)
    if fp in self.fingerprints:#这就是判重的核心操作。
        return True
    self.fingerprints.add(fp)
    ......

详见源代码:scrapy/dupefilters.py at master · scrapy/scrapy · GitHub

为了分布式,把这个集合也换掉吧,换了redis,照样也得把去重类给换了。
于是就有了scrapy-redis的dupefilter:scrapy-redis/dupefilter.py at master · darkrho/scrapy-redis · GitHub

——————————————把分割线掀起来(╯‵□′)╯︵||||||\\\\\\\\\\\\\————————————
那么依次类推,接下来的其他组件(Pipeline和Spider),我们也可以轻松的猜到,他们是为什么要被修改呢。对,都是因为redis,全怪redis,redis是罪魁祸首。(其实我不知道,我只是在凑字数而已)

以上是我个人见解,不代表权威说法。希望对你有帮助。如有纰漏请指正(但是别打我

 

参考:

[1]https://www.zhihu.com/question/32302268/answer/55724369   [知乎这篇scrapy-redis 和 scrapy 有什么区别,写的通俗易懂,讲解了分布式爬虫的原型]

[2]https://georgezouq.github.io/2016/06/27/%E5%9F%BA%E4%BA%8ERedis%E7%9A%84%E4%B8%89%E7%A7%8D%E5%88%86%E5%B8%83%E5%BC%8F%E7%88%AC%E8%99%AB%E7%AD%96%E7%95%A5/

[3]https://www.oschina.net/code/snippet_209440_20495

 

Scrapy: 基础

1.

scrapy.spiders.Spider

scrapy.spiders.Spider是Scrapy框架最核心部分之一,定义了如何爬取网站和获取结构化信息等。
查看源码发现Spider定义了from_crawler, sest_crawler, start_requests, make_requests_from_url, parse, update_settings, handles_request, close等function,而在官方文档规定了自定义的爬虫必须继承Spider类,要有至少以下几个模块:

  1. name: 必须,没有他scrapy crawl 找不到入口
  2. allowed_domains:可选,如果你怕从知乎爬到果壳,请可以定义一个字符串的list,并且OffsiteMiddleware 处于开启状态
  3. start_urls:一个URLs list,爬虫的起点网页
  4. custom_settings:仅在爬虫运行时覆盖来自settings的设置,低手不知道怎么玩
  5. logger: 一个日志记录者,以后再debug的时候再说吧
  6. from_crawler:这是Scrapy 用于创建自定义爬虫的类方法(class method),目前你不需要对他动手,这个方法会设置(set)crawlersettings
  7. settings:运行爬虫时的配置,是Settings的实例,低手不会玩
  8. crawler:在类初始化后由from_crawler设置,链接到绑定的spider的Crawler类,涉及到Crawler API ,低手用不来。
  9. start_requests():当start_urls有URLS即不为空时,会调用start_requests(),接着它会继续调用make_requests_from_url去Request每一个url。所以我们可以不用定义start_urls,而在这里自定义一个start_requests,使用其他Request,如FormRequest然后callbck(反馈)给自定义的parse。注:start_requests在爬虫运行只会执行一次。
  10. make_requests_from_url(url):前面说过,这个方法接收urls,返回reponse, 返回的response会默认(callback)传递给parse
  11. parse(response):如果没有自定义start_requests(),那么必须定义这个函数,并且在里面定义网页数据提取方法,十分重要哦。
  12. log(message[, level, component]):和上面的logger差不多,debug时候再仔细研究吧
  13. closed(reason):在爬虫关闭的时候调用,不太懂也不会用,这里先占位
    Link Extractors(链接提取器)是一类用来从返回网页中提取符合要求的链接
    Rule有以下几个参数
  14. link_extractor为LinkExtractor,用于定义需要提取的链接。
  15. callback参数:当link_extractor获取到链接时参数所指定的值作为回调函数。注:不能使用parse作为回调函数。
  16. follow:指定了根据该规则从response提取的链接是否需要跟进。callback为None,默认值为true。
  17. process_links:主要用来过滤由link_extractor获取到的链接。
  18. process_request:主要用来过滤在rule中提取到的request。

官方提供的例子:

import scrapy
from myproject.items import MyItem

class MySpider(scrapy.Spider):
    name = 'example.com'
    allowed_domains = ['example.com']

    def start_requests(self):
        yield scrapy.Request('http://www.example.com/1.html', self.parse)
        yield scrapy.Request('http://www.example.com/2.html', self.parse)
        yield scrapy.Request('http://www.example.com/3.html', self.parse)

    def parse(self, response):
        for h3 in response.xpath('//h3').extract():
            yield MyItem(title=h3)

        for url in response.xpath('//a/@href').extract():
            yield scrapy.Request(url, callback=self.parse)
参考:

[1]http://www.jianshu.com/p/3b24e168079b

爬虫: 图片

  1.  使用 run.py 运行不成功, 使用命令行可以   scrapy crawl jiandan
  2. Pillow 是用来生成缩略图,并将图片归一化为JPEG/RGB格式,因此为了使用图片管道,你需要安装这个库。 Python Imaging               Library (PIL) 在大多数情况下是有效的,但众所周知,在一些设置里会出现问题,因此我们推荐使用 Pillow 而不是PIL.

     

           咱们这次用到的就是Images Pipeline,用来下载图片,同时使用 Pillow 生成缩略图。在安装Scrapy的基础上,使用pip install pillow 安装这个模块。

  3. Traceback (most recent call last):
    File “/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/scrapy/pipelines/files.py”, line 356, in media_downloaded
    checksum = self.file_downloaded(response, request, info)
    File “/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/scrapy/pipelines/images.py”, line 98, in file_downloaded
    return self.image_downloaded(response, request, info)
    File “/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/scrapy/pipelines/images.py”, line 102, in image_downloaded
    for path, image, buf in self.get_images(response, request, info):
    File “/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/scrapy/pipelines/images.py”, line 115, in get_images
    orig_image = Image.open(BytesIO(response.body))
    File “/Users/saiwei/Library/Python/3.5/lib/python/site-packages/PIL/Image.py”, line 2319, in open
    % (filename if filename else fp))
    OSError: cannot identify image file <_io.BytesIO object at 0x1189982b0>

参考:

[1]https://scrapy-chs.readthedocs.io/zh_CN/1.0/topics/media-pipeline.html  [官方例子]

[2]http://www.cnblogs.com/qiyeboy/p/5449266.html   [详细例子]

[3]

爬虫: 提取吸血鬼日记下载地址

  1.  最近迷上吸血鬼日记,想提取该网页( http://www.dy2018.com/html/tv/oumeitv/20090911/21543.html )中吸血鬼日记第一季每集的下载链接,然后用迅雷进行下载
  2. 遇到的问题
    1.  网页用F12查看和代码爬的html有差别, (以后要以代码获取到的为准)
start_urls = [
# "http://localhost/index.html"
"http://www.dy2018.com/html/tv/oumeitv/20090911/21543.html"
] ;

def parse(self, response):

print("parse()")

sel = Selector(response)
# print("sel = ",sel.extract()) 将获取到的html打出来
result = "";

for res in sel.xpath("//a/text()").extract():

if "吸血鬼日记第一季" in res:
# print("res = ",res);
result += res+"\r\n";
print("result = ",result);

 

python: scrapy 模拟登录

  1.  
  2. 携带 cookies 进行页面访问
  3.  官方文档
    1. Using a dict:
      request_with_cookies = Request(url="http://www.example.com",
                                     cookies={'currency': 'USD', 'country': 'UY'})
      
    2. Using a list of dicts:
      request_with_cookies = Request(url="http://www.example.com",
                                     cookies=[{'name': 'currency',
                                              'value': 'USD',
                                              'domain': 'example.com',
                                              'path': '/currency'}])

      4.CookiesMiddleware 的使用 [TODO]

 

 

 

 

参考:

[1]http://www.pycoding.com/2016/04/12/scrapy-11.html

[2]http://cilab-undefine.github.io/2016/01/26/2016-01-26-scrapy%E4%BC%AA%E8%A3%85%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8F%8A%E6%A8%A1%E6%8B%9F%E7%99%BB%E9%99%86/

[3] https://doc.scrapy.org/en/latest/topics/request-response.html [官方文档]

[4]http://blog.javachen.com/2014/06/08/using-scrapy-to-cralw-zhihu.html [爬取知乎的模拟登录例子,这个详细]

[5]