当前位置: 首页 > news >正文

旅游电商网站建设方案模板一级服务器二级服务器

旅游电商网站建设方案模板,一级服务器二级服务器,深圳工程建设交易服务中心网站,玉树州wap网站建设公司1. 前言 1. 先看一个最简单的爬虫。 import requestsurl http://www.cricode.com r requests.get(url) print(r.text)2. 一个正常的爬虫程序 上面那个最简单的爬虫#xff0c;是一个不完整的残疾的爬虫。因为爬虫程序通常需要做的事情如下#xff1a; 1 http://www.cricode.com r requests.get(url) print(r.text)2. 一个正常的爬虫程序 上面那个最简单的爬虫是一个不完整的残疾的爬虫。因为爬虫程序通常需要做的事情如下 1给定的种子 URLs爬虫程序将所有种子 URL 页面爬取下来2爬虫程序解析爬取到的 URL 页面中的链接将这些链接放入待爬取 URL 集合中3重复 1、2 步直到达到指定条件才结束爬取 因此一个完整的爬虫大概是这样子的 import requests # 用来爬取网页 from bs4 import BeautifulSoup # 用来解析网页# 我们的种子 seeds [http://www.hao123.com,http://www.csdn.net,http://www.cricode.com ]# 设定终止条件为爬取到 100000个页面时就停止爬取 end_sum 0def do_save_action(textNone):passwhile end_sum 10000:if end_sum len(seeds):r requests.get(seeds[end_sum])end_sum end_sum 1do_save_action(r.text)soup BeautifulSoup(r.content)urls soup.find_all(a) # 解析网页for url in urls:seeds.append(url)else:break3. 现在来找茬。上面那个完整的爬虫缺点实在是太多。下面一一列举它的N宗罪 1我们的任务是爬取1万个网页按上面这个程序一个人在默默的爬取假设爬起一个网页3秒钟那么爬一万个网页需要3万秒钟。MGD我们应当考虑开启多个线程(池)去一起爬取或者用分布式架构去并发的爬取网页。2种子URL 和 后续解析到的URL 都放在一个列表里应该设计一个更合理的数据结构来存放这些待爬取的 URL 比如队列或者优先队列。( scrapy-redis 是 种子URL 在 redis的 list 里面后续解析到的URL 在 队列里面 )3对各个网站的 url我们一视同仁事实上我们应当区别对待。大站好站优先原则应当予以考虑。4每次发起请求都是根据 url 发起请求而这个过程中会牵涉到 DNS 解析将 url 转换成 ip 地址。一个网站通常由成千上万的 URL因此可以考虑将这些网站域名的 IP 地址进行缓存避免每次都发起 DNS 请求费时费力。5解析到网页中的 urls 后我们没有做任何去重处理全部放入待爬取的列表中。事实上可能有很多链接是重复的我们做了很多重复劳动。6….. 4.找了这么多茬后现在讨论一下问题的解决方案。 1并行爬取问题。我们可以有多种方法去实现并行。多线程或者线程池方式一个爬虫程序内部开启多个线程。同一台机器开启多个爬虫程序如此我们就有N多爬取线程在同时工作。能大大减少时间。此外当我们要爬取的任务特别多时一台机器、一个网点肯定是不够的我们必须考虑分布式爬虫。常见的分布式架构有主从Master——Slave架构、点对点Peer to Peer架构混合架构等。说到分布式架构那我们需要考虑的问题就有很多我们需要分派任务各个爬虫之间需要通信合作共同完成任务不要重复爬取相同的网页。分派任务我们要做到公平公正就需要考虑如何进行负载均衡。负载均衡我们第一个想到的就是Hash比如根据网站域名进行hash。负载均衡分派完任务之后千万不要以为万事大吉了万一哪台机器挂了呢原先指派给挂掉的哪台机器的任务指派给谁又或者哪天要增加几台机器任务有该如何进行重新分配呢 一个比较好的解决方案是用一致性 Hash 算法。2待爬取网页队列。如何对待待抓取队列跟操作系统如何调度进程是类似的场景。不同网站重要程度不同因此可以设计一个优先级队列来存放待爬起的网页链接。如此一来每次抓取时我们都优先爬取重要的网页。当然你也可以效仿操作系统的进程调度策略之多级反馈队列调度算法。3DNS缓存。为了避免每次都发起DNS查询我们可以将DNS进行缓存。DNS缓存当然是设计一个hash表来存储已有的域名及其IP。4网页去重。说到网页去重第一个想到的是垃圾邮件过滤。垃圾邮件过滤一个经典的解决方案是 Bloom Filter布隆过滤器。布隆过滤器原理简单来说就是建立一个大的位数组然后用多个 Hash 函数对同一个 url 进行 hash 得到多个数字然后将位数组中这些数字对应的位置为1。下次再来一个url时同样是用多个Hash函数进行hash得到多个数字我们只需要判断位数组中这些数字对应的为是全为1如果全为1那么说明这个url已经出现过。如此便完成了url去重的问题。当然这种方法会有误差只要误差在我们的容忍范围之类比如1万个网页我只爬取到了9999个也是可以忍受滴。。。5数据存储的问题。数据存储同样是个很有技术含量的问题。用关系数据库存取还是用 NoSQL或是自己设计特定的文件格式进行存储都大有文章可做。6进程间通信。分布式爬虫就必然离不开进程间的通信。我们可以以规定的数据格式进行数据交互完成进程间通信。7…… 如何实现上面这些东西 实现的过程中你会发现我们要考虑的问题远远不止上面这些。纸上得来终觉浅觉知此事要躬行 2. 如何 跟踪 和 过滤 在很多情况下我们并不是只抓取某个页面而需要 顺藤摸瓜从几个种子页面通过超级链接索最终定位到我们想要的页面。Scrapy 对这个功能进行了很好的抽象 from abc import ABCfrom scrapy.spiders import CrawlSpider, Rule from scrapy.linkextractors import LinkExtractor from scrapy.selector import Selector from scrapy.item import Itemclass Coder4Spider(CrawlSpider, ABC):name coder4allowed_domains [xxx.com]start_urls [http://www.xxx.com]rules (Rule(LinkExtractor(allow(page/[0-9],))),Rule(LinkExtractor(allow(archives/[0-9],)), callbackparse_item),)def parse_item(self, response):self.log(frequest url : {response.url})在上面我们用了 CrawlSpider 而不是 Spider。其中 name、 allowed_domains、start_urls 就不解释了。 重点说下 Rule 第 1 条不带 callback 的表示只是 “跳板”即只下载网页并根据 allow 中匹配的链接去继续遍历下一步的页面实际上 Rule 还可以指定 denyxxx 表示过滤掉哪些页面。 第 2 条带 callback 的是最终会回调 parse_item 函数的网页。 3. 如何 过滤重复 的页面 Scrapy 支持通过 RFPDupeFilter 来完成页面的去重防止重复抓取。 DUPEFILTER_CLASS scrapy.dupefilters.RFPDupeFilter RFPDupeFilter 实际是根据 request_fingerprint 实现过滤的。 源码中实现如下 def request_fingerprint(request, include_headersNone, keep_fragmentsFalse):if include_headers:include_headers tuple(to_bytes(h.lower()) for h in sorted(include_headers))cache _fingerprint_cache.setdefault(request, {})cache_key (include_headers, keep_fragments)if cache_key not in cache:fp hashlib.sha1()fp.update(to_bytes(request.method))fp.update(to_bytes(canonicalize_url(request.url, keep_fragmentskeep_fragments)))fp.update(request.body or b)if include_headers:for hdr in include_headers:if hdr in request.headers:fp.update(hdr)for v in request.headers.getlist(hdr):fp.update(v)cache[cache_key] fp.hexdigest()return cache[cache_key] 我们可以看到去重指纹是 sha1(method url body header)所以实际能够去掉重复的比例并不大。如果我们需要自己提取去重的 finger需要自己实现 Filter并配置上它。下面这个 Filter 只根据 url 去重 from scrapy.dupefilters import RFPDupeFilterclass SeenURLFilter(RFPDupeFilter):A dupe filter that considers the URLdef __init__(self, pathNone):self.urls_seen set()RFPDupeFilter.__init__(self, path)def request_seen(self, request):if request.url in self.urls_seen:return Trueelse:self.urls_seen.add(request.url)不要忘记配置上 DUPEFILTER_CLASS scraper.custom_filters.SeenURLFilter 4. 海量数据处理算法 Bloom Filter 海量数据处理算法—Bloom Filterhttps://www.cnblogs.com/zhxshseu/p/5289871.html 结合 Guava 源码解读布隆过滤器http://cyhone.com/2017/02/07/Introduce-to-BloomFilter/ 更多https://www.baidu.com/s?wdBloomfilter%20%E7%AE%97%E6%B3%95 Bloom-Filter即布隆过滤器1970年由 Bloom 中提出。是一种多哈希函数映射的快速查找算法。通常应用在一些需要快速判断某个元素是否属于集合但是并不严格要求100%正确的场合。Bloom Filter 有可能会出现错误判断但不会漏掉判断。也就是Bloom Filter 如果判断元素不在集合中那肯定就是不在。如果判断元素存在集合中有一定的概率判断错误。。。 因此Bloom Filter 不适合那些 零错误 的应用场合。而在能容忍低错误率的应用场合下Bloom Filter 比其他常见的算法如hash折半查找极大节省了空间。 优点是空间效率和查询时间都远远超过一般的算法缺点是有一定的误识别率和删除困难。一. 实例 为了说明 Bloom Filter 存在的重要意义举一个实例假设要你写一个网络蜘蛛web crawler。由于网络间的链接错综复杂蜘蛛在网络间爬行很可能会形成 “环”。为了避免形成“环”就需要知道蜘蛛已经访问过那些 URL。给一个 URL怎样知道蜘蛛是否已经访问过呢稍微想想就会有如下几种方案 1. 将访问过的 URL 保存到数据库。2. 用 HashSet 将访问过的 URL 保存起来。那只需接近 O(1) 的代价就可以查到一个 URL 是否被访问过了。3. URL 经过 MD5 或 SHA-1 等单向哈希后再保存到 HashSet 或数据库。4. Bit-Map 方法。建立一个 BitSet将每个 URL 经过一个哈希函数映射到某一位。 方法 1~3 都是将访问过的 URL 完整保存方法4 则只标记 URL 的一个映射位。以上方法在数据量较小的情况下都能完美解决问题但是当数据量变得非常庞大时问题就来了。 方法 1 的 缺点数据量变得非常庞大后关系型数据库查询的效率会变得很低。而且每来一个URL就启动一次数据库查询是不是太小题大做了方法 2 的 缺点太消耗内存。随着 URL 的增多占用的内存会越来越多。就算只有1亿个 URL每个 URL 只算 50 个字符就需要 5GB 内存。方法 3 由于字符串经过 MD5 处理后的信息摘要长度只有128BitSHA-1 处理后也只有 160Bit因此 方法3 比 方法2 节省了好几倍的内存。方法 4 消耗内存是相对较少的但缺点是单一哈希函数发生冲突的概率太高。还记得数据结构课上学过的 Hash 表冲突的各种解决方法么若要降低冲突发生的概率到1%就要将 BitSet 的长度设置为 URL 个数的 100 倍。 实质上上面的算法都忽略了一个重要的隐含条件允许小概率的出错不一定要100%准确也就是说少量 url 实际上没有没网络蜘蛛访问而将它们错判为已访问的代价是很小的——大不了少抓几个网页呗。 二. Bloom Filter 的算法 废话说到这里下面引入本篇的主角——Bloom Filter。其实上面方法4的思想已经很接近 Bloom Filter 了。方法四的致命缺点是冲突概率高为了降低冲突的概念Bloom Filter 使用了多个哈希函数而不是一个。 Bloom Filter 算法如下创建一个 m位 BitSet先将所有位初始化为0然后选择 k个 不同的哈希函数。第 i个 哈希函数对 字符串str 哈希的结果记为 histr且 histr的范围是 0 到 m-1 。 (1) 加入字符串过程。下面是每个字符串处理的过程首先是将字符串 str “记录” 到 BitSet 中的过程对于字符串 str分别计算 h1strh2str…… hkstr。然后将 BitSet 的第 h1str、h2str…… hkstr位设为1。下图是 Bloom Filter 加入字符串过程很简单吧这样就将字符串 str 映射到 BitSet 中的 k 个二进制位了。(2) 检查字符串是否存在的过程。下面是检查字符串str是否被BitSet记录过的过程对于字符串 str分别计算 h1strh2str…… hkstr。然后检查 BitSet 的第 h1str、h2str…… hkstr位是否为1若其中任何一位不为1则可以判定str一定没有被记录过。若全部位都是1则 “认为” 字符串 str 存在。若一个字符串对应的 Bit 不全为1则可以肯定该字符串一定没有被 Bloom Filter 记录过。这是显然的因为字符串被记录过其对应的二进制位肯定全部被设为1了。但是若一个字符串对应的Bit全为1实际上是不能100%的肯定该字符串被 Bloom Filter 记录过的。因为有可能该字符串的所有位都刚好是被其他字符串所对应这种将该字符串划分错的情况称为 false positive 。三. Bloom Filter 参数选择 (1) 哈希函数选择。哈希函数的选择对性能的影响应该是很大的一个好的哈希函数要能近似等概率的将字符串映射到各个Bit。选择k个不同的哈希函数比较麻烦一种简单的方法是选择一个哈希函数然后送入k个不同的参数。(2) m,n,k 值我们如何取值。我们定义 可能把不属于这个集合的元素误认为属于这个集合False Positive 不会把属于这个集合的元素误认为不属于这个集合False Negative。 哈希函数的个数 k、位数组大小 m、加入的字符串数量 n 的关系。哈希函数个数k取10位数组大小m设为字符串个数 n 的20倍时false positive 发生的概率是0.0000889 即10万次的判断中会存在 9 次误判对于一天1亿次的查询误判的次数为9000次。 哈希函数个数 k、位数组大小 m、加入的字符串数量 n 的关系可以参考参考文献 ( http://pages.cs.wisc.edu/~cao/papers/summary-cache/node8.html )。 Table 5: False positive rate under various m/n and k combinations.m/nkk17k18k19k20k21k22k23k242215.22.67e-05       2315.91.61e-05       2416.69.84e-061e-05      2517.36.08e-066.11e-066.27e-06     26183.81e-063.76e-063.8e-063.92e-06    2718.72.41e-062.34e-062.33e-062.37e-06    2819.41.54e-061.47e-061.44e-061.44e-061.48e-06   2920.19.96e-079.35e-079.01e-078.89e-078.96e-079.21e-07  3020.86.5e-076e-075.69e-075.54e-075.5e-075.58e-07  3121.54.29e-073.89e-073.63e-073.48e-073.41e-073.41e-073.48e-07 3222.22.85e-072.55e-072.34e-072.21e-072.13e-072.1e-072.12e-072.17e-07 该文献证明了对于给定的 m、n当 k ln(2)* m/n 时出错的概率是最小的。(log2 e ≈ 1.44倍)同时该文献还给出特定的kmn的出错概率。例如根据参考文献1哈希函数个数k取10位数组大小m设为字符串个数n的20倍时false positive 发生的概率是 0.0000889 这个概率基本能满足网络爬虫的需求了。 四. Python 实现 Bloom filter pybloomfiltermmap3  和 pybloom 是 不同 的包。。。。。 Python3 安装 pybloomfiltermmap3 pip install pybloomfiltermmap3 pybloomfiltermmap3 github 地址https://pypi.org/project/pybloomfiltermmap3/pybloomfiltermmap3 官方文档https://pybloomfiltermmap3.readthedocs.io/en/latest/pybloomfiltermmap 的 githubhttps://github.com/axiak/pybloomfiltermmap pybloomfiltermmap3 is a Python 3 compatible fork of pybloomfiltermmap by axiak。pybloomfiltermmap3 的目标在 python3 中为 bloom过滤器 提供一个快速、简单、可伸缩、正确的库。 Python 中文网https://www.cnpython.com/pypi/pybloomfiltermmap3 ################################################################# Windows 安装报错解决方法Python - 安装pybloomfilter遇到的问题及解决办法https://blog.csdn.net/tianbianEileen/article/details/75059132 Stack Overflow 上的回答如下 this problem looks like one “sys/mman.h:No such file or directory” And is a Unix header and is not available on Windows. I suggest you should ues pybloom instead on windows: pip install pybloom 通过 pypi 搜索发现最新的  pybloom 是 pybloom3 0.0.3 pybloom 的 github 地址https://github.com/Hexmagic/pybloom3 所以安装命令是pip install pybloom3 and you should use the package like this: from pybloom import BloomFilter ################################################################# pybloomfiltermmap3 快速示例https://pybloomfiltermmap3.readthedocs.io/en/latest/ BloomFilter.copy_template(filename[, perm0755]) → BloomFilter Creates a new BloomFilter object with the same parameters–same hash seeds, same size.. everything. Once this is performed, the two filters are comparable, so you can perform logical operators. Example: apple BloomFilter(100, 0.1, /tmp/apple)apple.add(apple) Falsepear apple.copy_template(/tmp/pear)pear.add(pear) Falsepear | apple BloomFilter.len(item) → Integer Returns the number of distinct elements that have been added to the BloomFilter object, subject to the error given in error_rate. bf BloomFilter(100, 0.1, /tmp/fruit.bloom)bf.add(Apple)bf.add(Apple)bf.add(orange)len(bf) 2bf2 bf.copy_template(/tmp/new.bloom)bf2 | bflen(bf2) Traceback (most recent call last):... pybloomfilter.IndeterminateCountError: Length of BloomFilter object is unavailable after intersection or union called. pybloom  快速示例 from pybloom import BloomFilter from pybloom import ScalableBloomFilterf BloomFilter(capacity1000, error_rate0.001)print([f.add(x) for x in range(10)]) # [False, False, False, False, False, False, False, False, False, False]print(all([(x in f) for x in range(10)])) # Trueprint(10 in f) # Falseprint(5 in f) # Truef BloomFilter(capacity1000, error_rate0.001) for i in range(0, f.capacity):_ f.add(i) print((1.0 - (len(f) / float(f.capacity))) f.error_rate 2e-18) # Truesbf ScalableBloomFilter(modeScalableBloomFilter.SMALL_SET_GROWTH) count 10000 for i in range(0, count):_ sbf.add(i)print((1.0 - (len(sbf) / float(count))) sbf.error_rate 2e-18) # True# len(sbf) may not equal the entire input length. 0.01% error is well # below the default 0.1% error threshold. As the capacity goes up, the # error will approach 0.1%.五Bloom Filter 的优缺点。 优点节约缓存空间空值的映射不再需要空值映射。减少数据库或缓存的请求次数。提升业务的处理效率以及业务隔离性。缺点存在误判的概率。传统的 Bloom Filter 不能作删除操作。六Bloom-Filter 的应用场景 Bloom-Filter 一般用于在大数据量的集合中判定某元素是否存在。 (1) 适用于一些黑名单,垃圾邮件等的过滤例如邮件服务器中的垃圾邮件过滤器。像网易QQ这样的公众电子邮件email提供商总是需要过滤来自发送垃圾邮件的人spamer的垃圾邮件。一个办法就是记录下那些发垃圾邮件的 email 地址。由于那些发送者不停地在注册新的地址全世界少说也有几十亿个发垃圾邮件的地址将他们都存起来则需要大量的网络服务器。如果用哈希表每存储一亿个 email地址就需要 1.6GB的内存用哈希表实现的具体办法是将每一个 email地址对应成一个八字节的信息指纹然后将这些信息指纹存入哈希表由于哈希表的存储效率一般只有 50%因此一个 email地址需要占用十六个字节。一亿个地址大约要 1.6GB即十六亿字节的内存。因此存贮几十亿个邮件地址可能需要上百 GB的内存。而 Bloom Filter 只需要哈希表 1/8 到 1/4 的大小就能解决同样的问题。BloomFilter 决不会漏掉任何一个在黑名单中的可疑地址。而至于误判问题常见的补救办法是在建立一个小的白名单存储那些可能别误判的邮件地址。(2) 在搜索引擎领域Bloom-Filte r最常用于网络蜘蛛(Spider)的 URL 过滤网络蜘蛛通常有一个 URL 列表保存着将要下载和已经下载的网页的 URL网络蜘蛛下载了一个网页从网页中提取到新的 URL 后需要判断该 URL 是否已经存在于列表中。此时Bloom-Filter 算法是最好的选择。 Google 的 BigTable。 Google 的 BigTable 也使用了 Bloom Filter以减少不存在的行或列在磁盘上的查询大大提高了数据库的查询操作的性能。 key-value 加快查询。 一般 Bloom-Filter 可以与一些 key-value 的数据库一起使用来加快查询。一般 key-value 存储系统的 values 存在硬盘查询就是件费时的事。将 Storage 的数据都插入Filter在 Filter 中查询都不存在时那就不需要去Storage 查询了。当 False Position 出现时只是会导致一次多余的Storage查询。 由于 Bloom-Filter 所用空间非常小所有 BF 可以常驻内存。这样子的话对于大部分不存在的元素只需要访问内存中的 Bloom-Filter 就可以判断出来了只有一小部分需要访问在硬盘上的 key-value 数据库。从而大大地提高了效率。如图 5. scrapy_redis 去重优化  7亿数据 原文链接https://blog.csdn.net/Bone_ACE/article/details/53099042 使用布隆去重代替scrapy_redis(分布式爬虫)自带的dupefilterhttps://blog.csdn.net/qq_36574108/article/details/82889744 背景 前些天接手了上一位同事的爬虫一个全网爬虫用的是 scrapy redis 分布式任务调度用的 scrapy_redis 模块。 大家应该知道 scrapy 是默认开启了去重的用了 scrapy_redis 后去重队列放在 redis 里面爬虫已经有7亿多条URL的去重数据了再加上一千多万条 requests 的种子redis 占用了160多G的内存服务器Centos7总共才175G好么。去重占用了大部分的内存不优化还能跑 一言不合就用 BloomfilterRedis 优化了一下内存占用立马降回到了二十多G保证漏失概率小于万分之一的情况下可以容纳50亿条URL的去重效果还是很不错的在此记录一下最后附上 ScrapyRedisBloomfilter 去重的 Demo可将去重队列和种子队列分开希望对使用 scrapy 框架的朋友有所帮助。 记录 我们要优化的是去重首先剥丝抽茧查看框架内部是如何去重的。 因为 scrapy_redis 会用自己 scheduler 替代 scrapy 框架的 scheduler 进行任务调度所以直接去 scrapy_redis 模块下查看scheduler.py 源码即可。 在 open() 方法中有句self.df load_object(self.dupefilter_cls).from_spider(spider)其中 load_object(self.dupefilter_cls) 是根据对象的绝对路径而载入一个对象并返回self.dupefilter_cls 就是 SCHEDULER_DUPEFILTER_CLASS scrapy_redis.dupefilter.RFPDupeFilterfrom_spider(spider) 是返回一个  RFPDupeFilter类 的实例。 再看下面的 enqueue_request() 方法 里面有句 if not request.dont_filter and self.df.request_seen(request) self.df.request_seen()这就是用来去重的了。按住Ctrl再左键点击request_seen查看它的代码可看到下面的代码 首先得到一个 request 的指纹然后使用 Redis 的 set 保存指纹。可见 scrapy_redis 是利用 set 数据结构来去重的去重的对象是 request 的 fingerprint。至于这个 fingerprint 到底是什么可以再深入去看 request_fingerprint() 方法的源码其实就是用 hashlib.sha1() 对 request 对象的某些字段信息进行压缩。我们用调试也可以看到其实 fp 就是 request 对象加密压缩后的一个字符串40个字符0~f。 是否可用 Bloomfilter 进行优化 以上步骤可以看出我们只要在 request_seen() 方法上面动些手脚即可。由于现有的七亿多去重数据存的都是这个 fingerprint所有 Bloomfilter 去重的对象仍然是 request 对象的 fingerprint。更改后的代码如下 def request_seen(self, request):fp request_fingerprint(request)if self.bf.isContains(fp): # 如果已经存在return Trueelse:self.bf.insert(fp)return Falseself.bf 是类 Bloomfilter() 的实例化关于这个Bloomfilter()类看下面的 基于 Redis 的 Bloomfilter 去重 以上优化的思路和代码就是这样以下将已有的七亿多的去重数据转成 Bloomfilter 去重。 内存将爆动作稍微大点机器就能死掉更别说Bloomfilter在上面申请内存了。当务之急肯定是将那七亿多个fingerprint导出到硬盘上而且不能用本机导并且先要将redis的自动持久化给关掉。因为常用Mongo所以习惯性首先想到Mongodb从redis取出2000条再一次性插入Mongo但速度还是不乐观瓶颈在于MongoDB。猜测是MongoDB对_id的去重导致的也可能是物理硬件的限制后来想用SSDB因为SSDB和Redis很相似用list存肯定速度快很多。然而SSDB唯独不支持Centos7其他版本的系统都可。。最后才想起来用txt这个最傻的方法却是非常有效的方法。速度很快只是为了防止读取时内存不足每100万个fingerprint存在了一个txt四台机器txt总共有七百个左右。fingerprint取出来后redis只剩下一千多万的Request种子占用内存9G。然后用Bloomfilter将txt中的fingerprint写回Redis写完以后Redis占用内存25G开启redis自动持久化后内存占用49G左右。6. 基于 Redis 的 Bloomfilter 去重 原文链接http://blog.csdn.net/bone_ace/article/details/53107018 前言 “去重” 是日常工作中会经常用到的一项技能在爬虫领域更是常用并且规模一般都比较大。去重需要考虑两个点去重的数据量、去重速度。为了保持较快的去重速度一般选择在内存中进行去重。 数据量不大时可以直接放在内存里面进行去重例如 python 可以使用 set() 进行去重。当去重数据需要持久化时可以使用 redis 的 set 数据结构。当数据量再大一点时可以用不同的加密算法先将长字符串压缩成 16/32/40 个字符再使用上面两种方法去重当数据量达到亿甚至十亿、百亿数量级时内存有限必须用 “位” 来去重才能够满足需求。Bloomfilter 就是将去重对象映射到几个内存“位”通过几个位的 0/1值来判断一个对象是否已经存在。然而 Bloomfilter 运行在一台机器的内存上不方便持久化机器 down 掉就什么都没啦也不方便分布式爬虫的统一去重。如果可以在 Redis 上申请内存进行 Bloomfilter以上两个问题就都能解决了。 本文即是用 Python 基于 Redis 实现 Bloomfilter 去重。下面先放代码最后附上说明。 代码 # encodingutf-8import redis from hashlib import md5class SimpleHash(object):def __init__(self, cap, seed):self.cap capself.seed seeddef hash(self, value):ret 0for i in range(len(value)):ret self.seed * ret ord(value[i])return (self.cap - 1) retclass BloomFilter(object):def __init__(self, hostlocalhost, port6379, db0, blockNum1, keybloomfilter)::param host: the host of Redis:param port: the port of Redis:param db: witch db in Redis:param blockNum: one blockNum for about 90,000,000; if you have more strings for filtering, increase it.:param key: the keys name in Redisself.server redis.Redis(hosthost, portport, dbdb)# Redis 的 String 类型最大容量为512M现使用 256M 2^8 * 2^20 字节 2^28 * 2^3 bitself.bit_size 1 31 self.seeds [5, 7, 11, 13, 31, 37, 61]self.key keyself.blockNum blockNumself.hashfunc []for seed in self.seeds:self.hashfunc.append(SimpleHash(self.bit_size, seed))def isContains(self, str_input):if not str_input:return Falsem5 md5()m5.update(str_input.encode(utf8))str_input m5.hexdigest()ret Truename self.key str(int(str_input[0:2], 16) % self.blockNum)for f in self.hashfunc:loc f.hash(str_input)ret ret self.server.getbit(name, loc)return retdef insert(self, str_input):m5 md5()m5.update(str_input.encode(utf8))str_input m5.hexdigest()name self.key str(int(str_input[0:2], 16) % self.blockNum)for f in self.hashfunc:loc f.hash(str_input)self.server.setbit(name, loc, 1)if __name__ __main__: 第一次运行时会显示 not exists!之后再运行会显示 exists! bf BloomFilter()if bf.isContains(http://www.baidu.com): # 判断字符串是否存在print(exists!)else:print(not exists!)bf.insert(http://www.baidu.com)说明 Bloomfilter 算法如何使用位去重这个百度上有很多解释。简单点说就是有几个 seeds现在申请一段内存空间一个seed 可以和字符串哈希映射到这段内存上的一个位几个位都为1即表示该字符串已经存在。插入的时候也是将映射出的几个位都置为1。 需要提醒一下的是 Bloomfilter 算法会有漏失概率即不存在的字符串有一定概率被误判为已经存在。这个概率的大小与seeds 的数量、申请的内存大小、去重对象的数量有关。下面有一张表m 表示内存大小多少个位n 表示去重对象的数量k 表示seed的个数。例如我代码中申请了256M即131m2^31约21.5亿。即 256 * 1024 *1024 * 8seed设置了7个。看k7那一列当漏失率为8.56e-05时m/n值为23。所以n 21.5/23 0.93(亿表示漏失概率为 8.56e-05 时256M 内存可满足0.93亿条字符串的去重。同理当漏失率为 0.000112 时256M内存可满足 0.98 亿条字符串的去重。 基于 Redis 的 Bloomfilter 去重其实就是利用了 Redis的String 数据结构但 Redis 一个 String 最大只能 512M所以如果去重的数据量大需要申请多个去重块代码中 blockNum 即表示去重块的数量。 代码中使用了 MD5 加密压缩将字符串压缩到了 32 个字符也可用 hashlib.sha1()压缩成40个字符。 它有两个作用 一是 Bloomfilter 对一个很长的字符串哈希映射的时候会出错经常误判为已存在压缩后就不再有这个问题 二是压缩后的字符为 0~f 共16中可能我截取了前两个字符再根据blockNum将字符串指定到不同的去重块进行去重。 总结 基于 Redis 的 Bloomfilter 去重既用上了 Bloomfilter 的海量去重能力又用上了 Redis 的可持久化能力基于 Redis 也方便分布式机器的去重。在使用的过程中要预算好待去重的数据量则根据上面的表适当地调整 seed 的数量和 blockNum 数量seed 越少肯定去重速度越快但漏失率越大。 7. scrapy_redis 种子优化 前言 继 scrapy_redis去重优化已有7亿条数据【 https://blog.csdn.net/bone_ace/article/details/53099042 】优化去重之后Redis 的内存消耗降了许多然而还不满足。这次对 scrapy_redis 的种子队列作了一些优化严格来说并不能用上“优化”这词其实就是结合自己的项目作了一些改进对本项目能称作优化对 scrapy_redis 未必是个优化。 scrapy_redis 默认是将 Request 对象序列化后变成一条字符串存入 Redis 作为种子需要的时候再取出来进行反序列化还原成一个 Request 对象。 现在的问题是序列化后的字符串太长短则几百个字符长则上千。我的爬虫平时至少也要维护包含几千万种子的种子队列占用内存在20G~50G之间Centos。想要缩减种子的长度这样不仅 Redis 的内存消耗会降低各个 slaver 从 Redis 拿种子的速度也会有所提高从而整个分布式爬虫系统的抓取速度也会有所提高效果视具体情况而定要看爬虫主要阻塞在哪里。 记录 1、首先看调度器即 scrapy_redis 模块下的 scheduler.py 文件可以看到 enqueue_request()方法和 next_request()方法就是种子 入队列 和 出队列 的地方self.queue 指的是我们在 setting.py 里面设定的 SCHEDULER_QUEUE_CLASS 值常用的是 scrapy_redis.queue.SpiderPriorityQueue。 2、进入 scrapy_redis 模块下的 queue.py 文件SpiderPriorityQueue 类的代码如下 class SpiderPriorityQueue(Base):Per-spider priority queue abstraction using redis sorted setdef __len__(self):Return the length of the queuereturn self.server.zcard(self.key)def push(self, request):Push a requestdata self._encode_request(request)pairs {data: -request.priority}self.server.zadd(self.key, **pairs)def pop(self, timeout0):Pop a requesttimeout not support in this queue classpipe self.server.pipeline()pipe.multi()pipe.zrange(self.key, 0, 0).zremrangebyrank(self.key, 0, 0)results, count pipe.execute()if results:return self._decode_request(results[0])可以看到上面用到了 Redis 的 zset 数据结构它可以给种子加优先级在进 Redis 之前用 _encode_request() 方法将Request 对象转成字符串_encode_request() 和 _decode_request 是 Base类下面的两个方法 def _encode_request(self, request):Encode a request objectreturn pickle.dumps(request_to_dict(request, self.spider), protocol-1)def _decode_request(self, encoded_request):Decode an request previously encodedreturn request_from_dict(pickle.loads(encoded_request), self.spider)可以看到这里先将 Request 对象转成一个字典再将字典序列化成一个字符串。Request 对象怎么转成一个字典呢看下面的代码一目了然。 def request_to_dict(request, spiderNone):Convert Request object to a dict.If a spider is given, it will try to find out the name of the spider methodused in the callback and store that as the callback.cb request.callbackif callable(cb):cb _find_method(spider, cb)eb request.errbackif callable(eb):eb _find_method(spider, eb)d {url: to_unicode(request.url), # urls should be safe (safe_string_url)callback: cb,errback: eb,method: request.method,headers: dict(request.headers),body: request.body,cookies: request.cookies,meta: request.meta,_encoding: request._encoding,priority: request.priority,dont_filter: request.dont_filter,}return d调试截图 注d 为 Request 对象转过来的字典data 为字典序列化后的字符串。 3、了解完 scrapy_redis 默认的种子处理方式现在针对自己的项目作一些调整。我的是一个全网爬虫每个种子需要记录的信息主要有两个url 和 callback 函数名。此时我们选择不用序列化直接用简单粗暴的方式将 callback 函数名和 url 拼接成一条字符串作为一条种子这样种子的长度至少会减少一半。另外我们的种子并不需要设优先级所以也不用 zset 了改用 Redis 的list。以下是我新建的 SpiderSimpleQueue 类加在 queue.py 中。如果在 settings.py 里将 SCHEDULER_QUEUE_CLASS 值设置成  scrapy_redis.queue.SpiderSimpleQueue 即可使用我这种野蛮粗暴的种子。 from scrapy.utils.reqser import request_to_dict, request_from_dict, _find_methodclass SpiderSimpleQueue(Base): url callback def __len__(self):Return the length of the queuereturn self.server.llen(self.key)def push(self, request):Push a requesturl request.urlcb request.callbackif callable(cb):cb _find_method(self.spider, cb)data %s--%s % (cb, url)self.server.lpush(self.key, data)def pop(self, timeout0):Pop a requestif timeout 0:data self.server.brpop(self.key, timeouttimeout)if isinstance(data, tuple):data data[1]else:data self.server.rpop(self.key)if data:cb, url data.split(--, 1)try:cb getattr(self.spider, str(cb))return Request(urlurl, callbackcb)except AttributeError:raise ValueError(Method %r not found in: %s % (cb, self.spider))__all__ [SpiderQueue, SpiderPriorityQueue, SpiderSimpleQueue, SpiderStack]4、另外需要提醒的是如果 scrapy 中加了中间件 process_request()当 yield 一个 Request 对象的时候scrapy_redis 会直接将它丢进 Redis 种子队列未执行 process_requset()需要一个 Request 对象的时候scrapy_redis 会从 Redis 队列中取出种子此时才会处理 process_request()方法接着去抓取网页。 所以并不需要担心 process_request()里面添加的 Cookie 在 Redis 中放太久会失效因为进 Redis 的时候它压根都还没执行process_request()。事实上 Request 对象序列化的时候带上的字段很多都是没用的默认字段很多爬虫都可以用 “callbackurl” 的方式来优化种子。 5、最后在 Scrapy_Redis_Bloomfilter https://github.com/LiuXingMing/Scrapy_Redis_Bloomfilter这个 demo 中我已作了修改大家可以试试效果。 结语 经过以上优化Redis 的内存消耗从 42G 降到了 27G里面包含7亿多条种子的去重数据 和 4000W 条种子。并且六台子爬虫的抓取速度都提升了一些。 两次优化内存消耗从160G降到现在的27G效果也是让人满意 原文链接http://blog.csdn.net/bone_ace/article/details/53306629 8. scrapy 引擎源码解析 本节内容将介绍下 scrapy 引擎具体实现的功能。 engine.py 提供了2个类Slot 和 ExecutionEngine Slot:  提供了几个方法添加请求删除请求关闭自己触发关闭方法。它使用 Twisted 的主循环 reactor 来不断的调度执行 Engine 的 _next_request 方法这个方法也是核心循环方法。ExecutionEngine:  引擎的执行任务 。 爬虫引擎 是 控制调度器下载器 和 爬虫 的。 This is the Scrapy engine which controls the Scheduler, Downloader and Spiders. For more information see docs/topics/architecture.rst 引擎 是 整个 scrapy 的核心控制和调度scrapy运行的。Engine 的 open_spider 方法完成了一些初始化以及启动调度器获取种子队列以及去重队列最后调用 self._nest_request 开始一次爬取过程。 open_spider 中 slot 调用 _next_request接下来我们看看 _next_request 先是通过 _needs_backout(spider) 判断是否需要结束爬虫然后返回然后通过 self._next_request_from_scheduler(spider) 方法判断是否还有 URL 需要去爬。 def _next_request(self, spider):slot self.slotif not slot:returnif self.paused:return while not self._needs_backout(spider): # 是否需要返回if not self._next_request_from_scheduler(spider): # 是否还有 URL 需要爬取breakif slot.start_requests and not self._needs_backout(spider):try:request next(slot.start_requests)except StopIteration:slot.start_requests Noneexcept Exception:slot.start_requests Nonelogger.error(Error while obtaining start requests,exc_infoTrue, extra{spider: spider})else:self.crawl(request, spider)if self.spider_is_idle(spider) and slot.close_if_idle:self._spider_idle(spider) _next_request 循环通过 _next_request_from_scheduler(self, spider) 方法从 scheduler 获取下一个需要爬取的 request然后送到下载器下载页面。 def _next_request_from_scheduler(self, spider):slot self.slotrequest slot.scheduler.next_request() # 从队列获取下一个待爬取的 requestif not request:returnd self._download(request, spider) # 使用 download 下载 requestd.addBoth(self._handle_downloader_output, request, spider) # 输出下载的 responsed.addErrback(lambda f: logger.info(Error while handling downloader output,exc_infofailure_to_exc_info(f),extra{spider: spider}))d.addBoth(lambda _: slot.remove_request(request))d.addErrback(lambda f: logger.info(Error while removing request from slot,exc_infofailure_to_exc_info(f),extra{spider: spider}))d.addBoth(lambda _: slot.nextcall.schedule())d.addErrback(lambda f: logger.info(Error while scheduling new request,exc_infofailure_to_exc_info(f),extra{spider: spider}))return d 继续看 _download(request, spider) 函数 ccdef _download(self, request, spider):slot self.slotslot.add_request(request)def _on_success(response):assert isinstance(response, (Response, Request))if isinstance(response, Response): # 如果返回的是 Response 对象打印日志response.request request # tie request to response receivedlogkws self.logformatter.crawled(request, response, spider)logger.log(*logformatter_adapter(logkws), extra{spider: spider})self.signals.send_catch_log(signalsignals.response_received, \responseresponse, requestrequest, spiderspider)return responsedef _on_complete(_):slot.nextcall.schedule()return _dwld self.downloader.fetch(request, spider) # 使用downloader的fetch下载requestdwld.addCallbacks(_on_success) # 添加成功回掉方法dwld.addBoth(_on_complete)return dwld scrapy源码分析 一 入口函数以及是如何运行 运行 scrapy crawl example 命令的时候就会执行我们写的爬虫程序。 下面我们从源码分析一下scrapy执行的流程入口函数以及是如何运行http://www.30daydo.com/article/530 Scrapy 阅读源码分析 原文链接https://blog.csdn.net/weixin_37947156/category_6959928.html scrapy 命令 当用 scrapy 写好一个爬虫后使用 scrapy crawl spider_name命令就可以运行这个爬虫那么这个过程中到底发生了什么 scrapy 命令从何而来 实际上当你成功安装 scrapy 后使用如下命令就能找到这个命令 $ which scrapy /usr/local/bin/scrapy 使用 vim 或其他编辑器打开它$ vim /usr/local/bin/scrapy 。其实它就是一个 python 脚本而且代码非常少。 #!/usr/bin/python # -*- coding: utf-8 -*- import re import sys from scrapy.cmdline import execute if __name__ __main__: sys.argv[0] re.sub(r(-script\.pyw|\.exe)?$, , sys.argv[0]) sys.exit(execute()) 安装 scrapy 后为什么入口点是这里呢 原因是在 scrapy 的安装文件 setup.py 中声明了程序的入口处 from os.path import dirname, join from setuptools import setup, find_packageswith open(join(dirname(__file__), scrapy/VERSION), rb) as f:version f.read().decode(ascii).strip() setup(nameScrapy,versionversion,urlhttp://scrapy.org,descriptionA high-level Web Crawling and Screen Scraping framework,long_descriptionopen(README.rst).read(),authorScrapy developers,maintainerPablo Hoffman,maintainer_emailpablopablohoffman.com,licenseBSD,packagesfind_packages(exclude(tests, tests.*)),include_package_dataTrue,zip_safeFalse,entry_points{console_scripts: [scrapy scrapy.cmdline:execute]},classifiers[Framework :: Scrapy,Development Status :: 5 - Production/Stable,Environment :: Console,Intended Audience :: Developers,License :: OSI Approved :: BSD License,Operating System :: OS Independent,Programming Language :: Python,Programming Language :: Python :: 2,Programming Language :: Python :: 2.7,Topic :: Internet :: WWW/HTTP,Topic :: Software Development :: Libraries :: Application Frameworks,Topic :: Software Development :: Libraries :: Python Modules,],install_requires[Twisted10.0.0,w3lib1.8.0,queuelib,lxml,pyOpenSSL,cssselect0.9,six1.5.2,], )entry_points 指明了入口是 cmdline.py 的 execute 方法在安装过程中setuptools 这个包管理工具就会把上述那一段代码生成放在可执行路径下。 入口(execute.py) 既然现在已经知道了 scrapy 的入口是 scrapy/cmdline.py 的 execute 方法我们来看一下这个方法。 def execute(argvNone, settingsNone):if argv is None:argv sys.argvif settings is None:settings get_project_settings()# set EDITOR from environment if availabletry:editor os.environ[EDITOR]except KeyError:passelse:settings[EDITOR] editorinproject inside_project()cmds _get_commands_dict(settings, inproject)cmdname _pop_command_name(argv)parser optparse.OptionParser(formatteroptparse.TitledHelpFormatter(),conflict_handlerresolve)if not cmdname:_print_commands(settings, inproject)sys.exit(0)elif cmdname not in cmds:_print_unknown_command(settings, cmdname, inproject)sys.exit(2)cmd cmds[cmdname]parser.usage scrapy %s %s % (cmdname, cmd.syntax())parser.description cmd.long_desc()settings.setdict(cmd.default_settings, prioritycommand)cmd.settings settingscmd.add_options(parser)opts, args parser.parse_args(argsargv[1:])_run_print_help(parser, cmd.process_options, args, opts)cmd.crawler_process CrawlerProcess(settings)_run_print_help(parser, _run_command, cmd, args, opts)sys.exit(cmd.exitcode) 函数主要是初始化项目配置在函数最后是初始化 CrawlerProcess 实例然后运行对应命令实例的run方法。如果运行命令是scrapy crawl spider_name则运行的就是 commands/crawl.py 的 run run方法中调用了 CrawlerProcess 实例的 crawl 和 start就这样整个爬虫程序就会运行起来了。 再来看 CrawlerProcess 初始化。scrapy.core.engine.py 其他代码省略。。。  class CrawlerProcess(CrawlerRunner):def __init__(self, settingsNone, install_root_handlerTrue):super(CrawlerProcess, self).__init__(settings)install_shutdown_handlers(self._signal_shutdown)configure_logging(self.settings, install_root_handler)log_scrapy_info(self.settings) 构造方法中调用了父类 CrawlerRunner 的构造 class CrawlerRunner:def __init__(self, settingsNone):if isinstance(settings, dict) or settings is None:settings Settings(settings)self.settings settings# 获取爬虫加载器self.spider_loader self._get_spider_loader(settings)self._crawlers set()self._active set()self.bootstrap_failed Falseself._handle_twisted_reactor() 初始化时调用了 _get_spider_loader 方法 默认配置文件中的 spider_loader 配置的是 scrapy.spiderloader.SpiderLoader 爬虫加载器会加载所有的爬虫脚本最后生成一个{spider_name: spider_cls}的字典。 执行 crawl 和 start 方法 CrawlerProcess 初始化完之后调用 crawl方法 这个过程会创建 Cralwer实例然后调用它的 crawl方法最后调用 start方法 reactor 是个什么东西呢它是 Twisted模块的事件管理器只要把需要执行的事件方法注册到reactor中然后调用它的run方法它就会帮你执行注册好的事件方法如果遇到网络IO等待它会自动帮你切换可执行的事件方法非常高效。 大家不用在意reactor是如何工作的你可以把它想象成一个线程池只是采用注册回调的方式来执行事件。 到这里爬虫的之后调度逻辑就交由引擎ExecuteEngine处理了。 scrapy 源码分析 系列 https://blog.csdn.net/happyAnger6/category_6085726_2.html scrapy 是一个基于 twisted 实现的开源爬虫要读懂其源码需要对twisted的异步编程模型有一定了解。可以通过之前3篇deferred的相关教程了解。 下面是总结的执行一个爬虫任务的整体执行流程请将图片放大查看即运行scrapy crawl  xxxSpider的执行流程 流程中主要的颜色框的含义如下 1.红色框是模块或者类。2.紫色框是向模块或者类发送的消息一般为函数调用。3.红色框垂直以下的黑色框即为本模块或者对象执行流程的伪代码描述。几个关键的模块和类介绍如下 cmdline命令行执行模块主要用于配置的获取并执行相应的ScrapyCommand。ScrapyCommand命令对象用于执行不同的命令。对于crawl任务主要是调用CrawlerProcess的crawl和start方法。CrawlerProcess顾名思义爬取进程主要用于管理Crawler对象可以控制多个Crawler对象来同时进行多个不同的爬取任务并调用Crawler的crawl方法。Crawler爬取对象用来控制爬虫的执行里面会通过一个执行引擎engine对象来控制spider从打开到启动等生命周期。ExecutionEngine执行引擎主要控制整个调度过程通过twisted的task.LoopingCall来不断的产生爬取任务。scrapy 源码解析 scrapyscrapy源码剖析https://www.cnblogs.com/shuimohei/p/13363462.html scrapy 源码解析 一启动流程源码分析(一)命令行启动https://www.cnblogs.com/qiu-hua/p/12930422.html scrapy 源码解析 二启动流程源码分析(二) CrawlerProcess 主进程https://www.cnblogs.com/qiu-hua/p/12930707.html scrapy 源码解析 三启动流程源码分析(三) ExecutionEngine 执行引擎https://www.cnblogs.com/qiu-hua/p/12930803.html scrapy 源码解析 四启动流程源码分析(四) Scheduler调度器https://www.cnblogs.com/qiu-hua/p/12932254.html scrapy 源码解析 五启动流程源码分析(五) Scraper刮取器https://www.cnblogs.com/qiu-hua/p/12932818.html   Python 之 Scrapy 框架源码解析https://blog.csdn.net/cui_yonghua/article/details/107040329 scrapy 信号 官网说明https://docs.scrapy.org/en/latest/topics/signals.html scrapy 基础组件专题四信号运用https://www.cnblogs.com/qiu-hua/p/12638683.html scrapy 的信号signal以及对下载中间件的一些总结https://blog.csdn.net/fiery_heart/article/details/82229871 9. DNS 解析缓存 原文链接https://blog.csdn.net/bone_ace/article/details/55000101 前言 这是 Python 爬虫中 DNS 解析缓存模块中的核心代码是去年的代码了现在放出来 有兴趣的可以看一下。 一般一个域名的 DNS 解析时间在 10~60 毫秒之间这看起来是微不足道但是对于大型一点的爬虫而言这就不容忽视了。例如我们要爬新浪微博同个域名下的请求有1千万这已经不算多的了那么耗时在 10~60 万秒之间一天才 86400 秒。也就是说单 DNS 解析这一项就用了好几天时间此时加上 DNS 解析缓存效果就明显了。 下面直接放代码说明在后面。 代码 # encodingutf-8 # --------------------------------------- # 版本0.1 # 日期2016-04-26 # 作者九茶bone_ace163.com # 开发环境Win64 Python 2.7 # ---------------------------------------import socket # from gevent import socket_dnscache {}def _setDNSCache(): DNS缓存 def _getaddrinfo(*args, **kwargs):if args in _dnscache:# print str(args) in cachereturn _dnscache[args]else:# print str(args) not in cache_dnscache[args] socket._getaddrinfo(*args, **kwargs)return _dnscache[args]if not hasattr(socket, _getaddrinfo):socket._getaddrinfo socket.getaddrinfosocket.getaddrinfo _getaddrinfo说明 其实也没什么难度就是将 socket 里面的缓存保存下来避免重复获取。可以将上面的代码放在一个 dns_cache.py 文件里爬虫框架里调用一下这个 _setDNSCache()方法就行了。 需要说明一下的是如果你使用了 gevent 协程并且用上了 monkey.patch_all()要注意此时爬虫已经改用 gevent 里面的socket 了DNS 解析缓存模块也应该要用 gevent 的 socket 才行。 10. Scrapy cookies 浅析 首先打消大家的疑虑 Scrapy 会自动管理 cookies 就像浏览器一样: Does Scrapy manage cookies automatically? Yes, Scrapy receives and keeps track of cookies sent by servers, and sends them back on subsequent requests, like any regular web browser does. Cookies 的管理是通过 CookiesMiddleware 它属于 DownloadMiddleware 的一部分所有的 requests 和 response 都要经过它的处理。 首先看下处理 request 的部分代码如下 class CookiesMiddleware(object):This middleware enables working with sites that need cookiesdef __init__(self, debugFalse):# 用字典生成多个cookiesjarself.jars defaultdict(CookieJar)self.debug debugdef process_request(self, request, spider):if request.meta.get(dont_merge_cookies, False):return# 每个cookiesjar的key都存储在 meta字典中cookiejarkey request.meta.get(cookiejar)jar self.jars[cookiejarkey]cookies self._get_request_cookies(jar, request)# 把requests的cookies存储到cookiesjar中for cookie in cookies:jar.set_cookie_if_ok(cookie, request)# set Cookie header# 删除原有的cookiesrequest.headers.pop(Cookie, None)# 添加cookiesjar中的cookies到requests headerjar.add_cookie_header(request)self._debug_cookie(request, spider) 流程如下: 使用字典初始化多个 cookies jar把每个 requests 指定的 cookies jar 提取出来然后根据 policy 把 requests 中的 cookies 添加 cookies jar最后把 cookies jar 中合适的 cookies 添加到 requests 首部 接下来看看如何处理 response 中的 cookies def process_response(self, request, response, spider):if request.meta.get(dont_merge_cookies, False):return response# extract cookies from Set-Cookie and drop invalid/expired cookiescookiejarkey request.meta.get(cookiejar)jar self.jars[cookiejarkey]jar.extract_cookies(response, request)self._debug_set_cookie(response, spider)return response 流程如下: 首先从 cookies jar 字典中把 requests 对应的 cookiesjar 提取出来.使用 extract_cookies 把 response 首部中的 cookies 添加到 cookies jar11. 扩展部分 python 之 goose3 库 --- 文章提取工具 github 地址https://github.com/goose3/goose3 goose3 官网文档https://goose3.readthedocs.io/en/latest/ goose3 是什么 GOOSE3 最初是用 Java 编写的一篇文章提取器最近将它Auff2011转换成Scala项目这是 python 中的完全重写。该软件的目标是获取任何新闻文章或文章类型的网页不仅提取文章的主体而且还提取所有元数据和图片。 官方网站https://github.com/goose3/goose3 安装 pip install goose3 mkvirtualenv --no-site-packages goose3 git clone https://github.com/goose3/goose3.git cd goose3 pip install -r ./requirements/python python setup.py install 使用 示例用法https://pypi.org/project/goose3/3.0.4/ python 之 goose3 库https://blog.csdn.net/weixin_42547344/article/details/100735035 动手实践 CURL CURL 是利用 URL 语法在命令行方式下工作的开源文件传输工具。它支持http、https、ftp、ftps、telnet 等多种协议常被用来抓取网页和监控Web服务器状态。 CURL 使用 curl 命令可以用来构造http请求。 通用语法curl [option] [URL...] 使用实例 curl 是 Linux下一个很强大的 http 命令行工具其功能十分强大。 基本用法 curl http://www.baidu.com抓取 www.ip138.com 查询网 如发现乱码可以使用iconv转码 curl http://ip138.com|iconv -f gb2312回车之后html显示在屏幕上了 ~ 1.1 get方式提交数据 curl -G -d namevaluename2value2 http://www.baidu.com1.2 post方式提交数据 curl -d namevaluename2value2 http://www.baidu.com #post数据 curl -d abcdtxt/tmp/txt http://www.baidu.com #post文件以表单的方式上传文件 curl -F file/tmp/me.txt http://www.aiezu.com相当于设置form表单的methodPOST和enctypemultipart/form-data两个属性。 保存访问的网页 curl http://www.baidu.com page.html或者用 curl 的内置 option 就好存下 http 的结果用这个 option: -o curl -o page.html http://www.baidu.comcurl -O http://sh.meituan.com/shop/42030772% Total % Received % Xferd Average Speed Time Time Time CurrentDload Upload Total Spent Left Speed 100 159k 0 159k 0 0 328k 0 --:--:-- --:--:-- --:--:-- 328k下载过程中标准输出还会显示下载的统计信息,比如进度、下载字节数、下载速度等 这样自动保存文件42030772看到屏幕上出现一个下载页面进度指示。显示100%则表示保存成功 设置 Header curl -H Host: 157.166.226.25-H Accept-Language: es-H Cookie: ID1234 http://cnn.com显示文档信息 -I显示文档信息 curl -I http://www.sina.com.cn/ -H Accept-Encoding:gzip,defalte指定proxy服务器以及其端口 -x 可以指定http访问所使用的proxy服务器及其端口 curl -x 123.45.67.89:1080 -o page.html http://www.linuxidc.com curl -x http://username:pwdip:port http://www.baidu.com使用cookie 有些网站是使用cookie来记录session信息。对于chrome这样的浏览器可以轻易处理cookie信息但在curl中只要增加相关参数也是可以很容易的处理cookie -c 保存http的response里面的cookie信息。 curl -c cookiec.txt http://www.baidu.com执行后cookie信息就被存到了cookiec.txt里面了 -D 保存http的response里面的header信息 curl -D cookied.txt http://www.baidu.com执行后cookie信息就被存到了cookied.txt里面了 注意-c(小写)产生的cookie和-D里面的cookie是不一样的。 -b使用cookie 很多网站都是通过监视你的cookie信息来判断你是否按规矩访问他们的网站的因此我们需要使用保存的cookie信息。 curl -b cookiec.txt http://www.baidu.com模仿浏览器信息 有些网站需要使用特定的浏览器去访问他们有些还需要使用某些特定的版本。 -A :指定浏览器去访问网站 curl -A Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.0) http://www.baidu.com这样服务器端就会认为是使用IE8.0去访问的 伪造referer盗链 很多服务器会检查http访问的referer从而来控制访问。比如你是先访问首页然后再访问首页中的邮箱页面这里访问邮箱的referer地址就是访问首页成功后的页面地址如果服务器发现对邮箱页面访问的referer地址不是首页的地址就断定那是个盗连了 -e设定referer curl -e www.baidu.com http://news.baidu.com/这样就会让服务器其以为你是从www.baidu.com点击某个链接过来的 下载文件 9.1 -o/-O文件下载 -o 把输出写到该文件中 curl -o dodo1.jpg http://www.shaimn.com/uploads/allimg/160613/1-160613121111.jpg-O把输出写到该文件中保留远程文件的文件名 curl -O http://www.shaimn.com/uploads/allimg/160613/1-160613121111.jpg这样就会以服务器上的名称保存文件到本地 9.2 循环下载 有时候下载图片可以能是前面的部分名称是一样的就最后的尾椎名不一样 curl -O http://www.shaimn.com/uploads/allimg/160613/1-16061312111[1-5].jpg这样就会把 1-16061312111.jpg、 1-16061312112.jpg、 1-16061312113.jpg、 1-16061312114.jpg、 1-16061312115.jpg 全部保存下来 9.3 下载重命名 curl http://www.shaimn.com/uploads/allimg/160613/1-16061312111[1-5].jpg -o dodo#1.jpgdodo1.jpgdodo2.jpgdodo3.jpgdodo4.jpgdodo5.jpg 9.4 分块下载 有时候下载的东西会比较大这个时候我们可以分段下载。使用内置option-r curl -r 0-100 -o dodo1_part1.JPG http://www.shaimn.com/uploads/allimg/160613/1-160613121111.jpg curl -r 100-200 -o dodo1_part2.JPG http://www.shaimn.com/uploads/allimg/160613/1-160613121111.jpg curl -r 200- -o dodo1_part3.JPG http://www.shaimn.com/uploads/allimg/160613/1-160613121111.jpg cat dodo1_part* dodo1.JPG这样就可以查看dodo1.JPG的内容了 9.5 通过ftp下载文件 curl可以通过ftp下载文件curl提供两种从ftp中下载的语法 curl -O -u 用户名:密码 ftp://www.linux.com/dodo1.JPG curl -O ftp://用户名:密码www.linux.com/dodo1.JPG9.6 显示下载进度条 curl -# -O http://www.linux.com/dodo1.JPG9.7不会显示下载进度信息 curl -s -O http://www.linux.com/dodo1.JPG断点续传 在windows中我们可以使用迅雷这样的软件进行断点续传。 curl可以通过内置option:-C同样可以达到相同的效果 如果在下载dodo1.JPG的过程中突然掉线了可以使用以下的方式续传 curl -C -O http://www.linux.com/dodo1.JPG通过使用-C选项可对大文件使用断点续传功能如# 当文件在下载完成之前结束该进程 curl -O http://www.gnu.org/software/gettext/manual/gettext.html ############## 20.1%# 通过添加-C选项继续对该文件进行下载已经下载过的文件不会被重新下载 curl -C - -O http://www.gnu.org/software/gettext/manual/gettext.html ############### 21.1%上传文件 curl不仅仅可以下载文件还可以上传文件。通过内置option:-T来实现 # curl -T dodo1.JPG -u 用户名:密码 ftp://www.linux.com/img/这样就向ftp服务器上传了文件dodo1.JPG 显示抓取错误 # curl -f http://www.linux.com/error对 CURL 使用网络限速 通过--limit-rate选项对CURL的最大网络使用进行限制 下载速度最大不会超过1000B/secondcurl --limit-rate 1000B -O http://www.gnu.org/software/gettext/manual/gettext.htmllinux curl 命令 -a/--append 上传文件时附加到目标文件 -A/--user-agent string 设置用户代理发送给服务器 - anyauth 可以使用“任何”身份验证方法 -b/--cookie namestring/file cookie字符串或文件读取位置 - basic 使用HTTP基本验证 -B/--use-ascii 使用ASCII /文本传输 -c/--cookie-jar file 操作结束后把cookie写入到这个文件中 -C/--continue-at offset 断点续转 -d/--data data HTTP POST方式传送数据 --data-ascii data 以ascii的方式post数据 --data-binary data 以二进制的方式post数据 --negotiate 使用HTTP身份验证 --digest 使用数字身份验证 --disable-eprt 禁止使用EPRT或LPRT --disable-epsv 禁止使用EPSV -D/--dump-header file 把header信息写入到该文件中 --egd-file file 为随机数据(SSL)设置EGD socket路径 --tcp-nodelay 使用TCP_NODELAY选项 -e/--referer 来源网址 -E/--cert cert[:passwd] 客户端证书文件和密码 (SSL) --cert-type type 证书文件类型 (DER/PEM/ENG) (SSL) --key key 私钥文件名 (SSL) --key-type type 私钥文件类型 (DER/PEM/ENG) (SSL) --pass pass 私钥密码 (SSL) --engine eng 加密引擎使用 (SSL). --engine list for list --cacert file CA证书 (SSL) --capath directory CA目录 (made using c_rehash) to verify peer against (SSL) --ciphers list SSL密码 --compressed 要求返回是压缩的形势 (using deflate or gzip) --connect-timeout seconds 设置最大请求时间 --create-dirs 建立本地目录的目录层次结构 --crlf 上传是把LF转变成CRLF -f/--fail 连接失败时不显示http错误 --ftp-create-dirs 如果远程目录不存在创建远程目录 --ftp-method [multicwd/nocwd/singlecwd] 控制CWD的使用 --ftp-pasv 使用 PASV/EPSV 代替端口 --ftp-skip-pasv-ip 使用PASV的时候,忽略该IP地址 --ftp-ssl 尝试用 SSL/TLS 来进行ftp数据传输 --ftp-ssl-reqd 要求用 SSL/TLS 来进行ftp数据传输 -F/--form namecontent 模拟http表单提交数据 -form-string namestring 模拟http表单提交数据 -g/--globoff 禁用网址序列和范围使用{}和[] -G/--get 以get的方式来发送数据 -h/--help 帮助 -H/--header line自定义头信息传递给服务器 --ignore-content-length 忽略的HTTP头信息的长度 -i/--include 输出时包括protocol头信息 -I/--head 只显示文档信息 从文件中读取-j/--junk-session-cookies忽略会话Cookie - 界面interface指定网络接口/地址使用 - krb4 级别启用与指定的安全级别krb4 -j/--junk-session-cookies 读取文件进忽略session cookie --interface interface 使用指定网络接口/地址 --krb4 level 使用指定安全级别的krb4 -k/--insecure 允许不使用证书到SSL站点 -K/--config 指定的配置文件读取 -l/--list-only 列出ftp目录下的文件名称 --limit-rate rate 设置传输速度 --local-portNUM 强制使用本地端口号 -m/--max-time seconds 设置最大传输时间 --max-redirs num 设置最大读取的目录数 --max-filesize bytes 设置最大下载的文件总量 -M/--manual 显示全手动 -n/--netrc 从netrc文件中读取用户名和密码 --netrc-optional 使用 .netrc 或者 URL来覆盖-n --ntlm 使用 HTTP NTLM 身份验证 -N/--no-buffer 禁用缓冲输出 -o/--output 把输出写到该文件中 -O/--remote-name 把输出写到该文件中保留远程文件的文件名 -p/--proxytunnel 使用HTTP代理 --proxy-anyauth 选择任一代理身份验证方法 --proxy-basic 在代理上使用基本身份验证 --proxy-digest 在代理上使用数字身份验证 --proxy-ntlm 在代理上使用ntlm身份验证 -P/--ftp-port address 使用端口地址而不是使用PASV -Q/--quote cmd文件传输前发送命令到服务器 -r/--range range检索来自HTTP/1.1或FTP服务器字节范围 --range-file 读取SSL的随机文件 -R/--remote-time 在本地生成文件时保留远程文件时间 --retry num 传输出现问题时重试的次数 --retry-delay seconds 传输出现问题时设置重试间隔时间 --retry-max-time seconds 传输出现问题时设置最大重试时间 -s/--silent静音模式。不输出任何东西 -S/--show-error 显示错误 --socks4 host[:port] 用socks4代理给定主机和端口 --socks5 host[:port] 用socks5代理给定主机和端口 --stderr file -t/--telnet-option OPTval Telnet选项设置 --trace file 对指定文件进行debug --trace-ascii file Like --跟踪但没有hex输出 --trace-time 跟踪/详细输出时添加时间戳 -T/--upload-file file 上传文件 --url URL Spet URL to work with -u/--user user[:password]设置服务器的用户和密码 -U/--proxy-user user[:password]设置代理用户名和密码 -v/--verbose -V/--version 显示版本信息 -w/--write-out [format]什么输出完成后 -x/--proxy host[:port]在给定的端口上使用HTTP代理 -X/--request command指定什么命令 -y/--speed-time 放弃限速所要的时间。默认为30 -Y/--speed-limit 停止传输速度的限制速度时间秒 -z/--time-cond 传送时间设置 -0/--http1.0 使用HTTP 1.0 -1/--tlsv1 使用TLSv1SSL -2/--sslv2 使用SSLv2的SSL -3/--sslv3 使用的SSLv3SSL --3p-quote like -Q for the source URL for 3rd party transfer --3p-url 使用url进行第三方传送 --3p-user 使用用户名和密码进行第三方传送 -4/--ipv4 使用IP4 -6/--ipv6 使用IP6 -#/--progress-bar 用进度条显示当前的传送状态 一些常见的限制方式 上述都是讲的都是一些的基础的知识现在我就列一些比较常见的限制方式如何突破这些限制抓取数据。 Basic Auth 一般会有用户授权的限制会在headers的Autheration字段里要求加入 Referer 通常是在访问链接时必须要带上Referer字段服务器会进行验证例如抓取京东的评论 User-Agent 会要求真是的设备如果不加会用编程语言包里自有User-Agent可以被辨别出来 Cookie 一般在用户登录或者某些操作后服务端会在返回包中包含Cookie信息要求浏览器设置Cookie没有Cookie会很容易被辨别出来是伪造请求 也有本地通过JS根据服务端返回的某个信息进行处理生成的加密信息设置在Cookie里面 Gzip 请求headers里面带了gzip返回有时候会是gzip压缩需要解压 JavaScript 加密操作 一般都是在请求的数据包内容里面会包含一些被javascript进行加密限制的信息例如新浪微博会进行SHA1和RSA加密之前是两次SHA1加密然后发送的密码和用户名都会被加密 其他字段 因为http的headers可以自定义地段所以第三方可能会加入了一些自定义的字段名称或者字段值这也是需要注意的。 真实的请求过程中其实不止上面某一种限制可能是几种限制组合在一次比如如果是类似RSA加密的话可能先请求服务器得到Cookie然后再带着Cookie去请求服务器拿到公钥然后再用js进行加密再发送数据到服务器。所以弄清楚这其中的原理并且耐心分析很重要。 防封禁策略 Scrapy: http://doc.scrapy.org/en/master/topics/practices.html#avoiding-getting-banned 如何让你的 scrapy 爬虫不再被 ban 根据 scrapy 官方文档https://docs.scrapy.org/en/master/topics/practices.html#avoiding-getting-banned 里面的描述要防止 scrapy 被 ban主要有以下几个策略。 动态设置 user agent禁用 cookies设置延迟下载使用 Google cache使用IP地址池Tor project、VPN和代理IP使用 Crawlera 由于 Google cache 受国内网络的影响你懂得 所以主要从动态随机设置user agent、禁用cookies、设置延迟下载和使用代理IP这几个方式。 本文以 cnblogs 为例 创建 middlewares.py scrapy代理IP、user agent 的切换都是通过 DOWNLOADER_MIDDLEWARES 进行控制下面我们创建 middlewares.py文件。 [rootbogon cnblogs]# vi cnblogs/middlewares.py如下内容 import random import base64 from settings import PROXIESclass RandomUserAgent(object):Randomly rotate user agents based on a list of predefined onesdef __init__(self, agents):self.agents agentsclassmethoddef from_crawler(cls, crawler):return cls(crawler.settings.getlist(USER_AGENTS))def process_request(self, request, spider):#print ************************** random.choice(self.agents)request.headers.setdefault(User-Agent, random.choice(self.agents))class ProxyMiddleware(object):def process_request(self, request, spider):proxy random.choice(PROXIES)if proxy[user_pass] is not None:#request.meta[proxy] http://YOUR_PROXY_IP:PORTrequest.meta[proxy] http://%s % proxy[ip_port]#proxy_user_pass USERNAME:PASSWORDencoded_user_pass base64.encodestring(proxy[user_pass])request.headers[Proxy-Authorization] Basic encoded_user_passprint **************ProxyMiddleware have pass************ proxy[ip_port]else:print **************ProxyMiddleware no pass************ proxy[ip_port]request.meta[proxy] http://%s % proxy[ip_port]类 RandomUserAgent 主要用来动态获取 user agentuser agent 列表 USER_AGENTS 在 settings.py 中进行配置。 类 ProxyMiddleware 用来切换代理proxy 列表 PROXIES 也是在 settings.py 中进行配置。 如果你用的是 socks5 代理那么对不起目前 scrapy 还不能直接支持可以通过 Privoxy 等软件将其本地转化为 http 代理 修改 settings.py 配置 USER_AGENTS 和 PROXIES USER_AGENTS [Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727),Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506),Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.35; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727),Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US),Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0),Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322),Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30),Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30),Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527 (KHTML, like Gecko, Safari/419.3) Arora/0.6,Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1,Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0,Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5,Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6,Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11,Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.20 (KHTML, like Gecko) Chrome/19.0.1036.7 Safari/535.20,Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52, ]PROXIES [{ip_port: 111.11.228.75:80, user_pass: },{ip_port: 120.198.243.22:80, user_pass: },{ip_port: 111.8.60.9:8123, user_pass: },{ip_port: 101.71.27.120:80, user_pass: },{ip_port: 122.96.59.104:80, user_pass: },{ip_port: 122.224.249.122:8088, user_pass: }, ]代理 IP可以网上搜索一下上面的代理IP获取自http://www.xici.net.co/ 禁用 cookies COOKIES_ENABLED False设置下载延迟 DOWNLOAD_DELAY3设置 DOWNLOADER_MIDDLEWARES  DOWNLOADER_MIDDLEWARES {cnblogs.middlewares.RandomUserAgent: 1,scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware: 110,cnblogs.middlewares.ProxyMiddleware: 100, }保存 settings.py 3、测试 [rootbogon cnblogs]# scrapy crawl CnblogsSpider本文的 user agent 和 proxy 列表都是采用 settings.py 的方式进行设置的实际生产中 user agent 和 proxy 有可能会经常更新每次更改配置文件显得很笨拙也不便于管理。因而可以根据需要保存在 mysql 数据库 SSL中间人监测关键技术 --- SSL会话劫持 数据流重定向技术是SSL中间人监测的基础该技术的使用使得被监测主机与SSL服务器的通信流量都会经过监测主机。对于一般的中间人监测来说再加上数据转发机制就已经足够。但对于SSL中间人监测来说仅仅通过数据流重定向得到的都是经过加密后的数据无法直接用来进行HTTP协议解析。故此必需使用SSL会话劫持技术才能得到被监测主机与SSL服务器之间通信数据的明文。 自SSL问世以来在其应用范围越来越广泛同时多种针对SSL协议本身的缺陷或者其不规范引用的SSL会话劫持方法也随之出现下面将详细分析两种典型的SSL会话劫持的实现原理和实现条件。 一、利用伪造的 X.509 证书 1.1 会话劫持原理 当 SSL 客户端与 SSL 服务端建立连接时在正常的连接握手阶段客户端必定会要求服务端出示其X.509公钥证书并根据以下3个要素验证服务器证书的有效性 a 该公钥证书的subject name(主题名)和所访问的服务器站点的名称是否一致b 该公钥证书的是否过期c 该公钥证书及其签发者证书链中的证书的数字签名是否有效层层验证一直验证到根CA证书为止。 当 SSL 客户端访问一个基于 HTTPS 的加密 Web 站点时只要上述三个要素有一个验证没有通过SSL 协议就会发出告警大多数浏览器会弹出一个提示框提示服务器证书存在的问题但不会直接断开SSL连接而是让用户决定是否继续。下图展示了IE 浏览器弹出的安全警报提示框。 大多数浏览器在验证到服务器证书存在问题后的处理方式是存在巨大隐患的因为用户往往由于缺乏安全意识或者图方便而选择接受不安全的证书这就使得伪造一个和合法证书极为相似的“伪证书”骗取 SSL 客户端用户信任的手段成为可能。下图展示了这种 SSL 会话劫持的主要流程图中C 为 SSL 客户端M 为监测主机S 为 SSL 服务端 上图就是基于伪造证书进行劫持的流程文字描述如下 主机M通过数据流重定向技术使得主机C与主机S之间的通信流量都流向主机M主机C本欲与主机S建立SSL连接但发送的连接建立请求被重定向到了主机M 主机C首先与主机M建立TCP连接然后向主机M发起SSL连接请求 主机M收到来自主机C的连接请求后首先与主机S建立TCP连接然后向主机S发起SSL连接请求 主机S响应主机M的请求由此主机M与主机S之间成功建立SSL连接主机M同时获得主机S的X.509公钥证书Certificate_S 主机M根据Certificate_S中的关键信息主要是subject name、有效期限等伪造一个极相似的自签名证书Certificate_S’,并以此证书响应第②步中来自主机C的SSL连接请求 主机C的浏览器验证Certificate_S’的有效性发现subject name与请求的站点名称一致证书还在有效期内但是并非由信任的机构颁发。于是弹出提示框让用户选择是否继续。由于Certificate_S’与Certificate_S从外表上几乎看不出来差别大部分用户会选择继续 这是SSL会话劫持可以成功的关键 由此主机C与主机M成功建立SSL连接。 这样以后主机C发往SSL服务端的数据主机M可以捕获并解密查看主机S返回给SSL客户端的数据主机M也可以捕获并解密查看。至此主机M实现了完整的SSL中间人监测。 经过以上步骤主机M成功实现了主机CSSL客户端与主机SSSL服务端之间的会话劫持并可以对明文形式的会话内容进行监测。 1.2 成功的必要条件 这种类型的 SSL 会话劫持成功的必要条件如下 a 能够通过ARP欺骗、DNS欺骗或者浏览器数据重定向等欺骗技术使得SSL客户端C和服务端S之间的数据都流向中间人监测主机b SSL客户端在接收到伪造的X.509证书后用户选择信任该证书并继续SSL连接c SSL服务端未要求对SSL客户端进行认证。二、利用 HTTP 与 HTTPS 之间跳转的验证漏洞 2.1 会话劫持原理 用户浏览网页时使用 SSL 协议的方式一般有两种。一种是在浏览器地址栏输入网址时直接指定协议类型为HTTPS另一种是通过HTTP响应的302状态将网页重定向到HTTPS 链接。2009年2月在美国拉斯维加斯举行的BlackHat黑客大会上安全研究人员Moxie Marlinspike 演示了通过自己研发的SSLstrip工具劫持SSL会话来截获注册数据的方法为SSL会话劫持提供了新思路。 SSLstrip 使用了社会工程学的原理许多人为了图方便省事在输入网址时一般不考虑传输协议习惯上只是简单输入主机名浏览器默认在这种情况下会使用 HTTP 协议。例如用户为了使用Gmail邮箱直接输入accounts.google.com浏览器会给谷歌服务器发送一个HTTP 请求谷歌服务器认为电子邮件属于应加密的重要事务使用HTTP不恰当应改为使用HTTPS于是它返回一个状态码为302的HTTP 响应给出一个重定向网址https://accounts.google.com/ServiceLogin?passive1209600continuehttps%3A%2F%2Faccounts.google.com%2FManageAccountfollowuphttps%3A%2F%2Faccounts.google.com%2FManageAccount浏览器再使用这个重定向网址发出HTTPS 请求。 一个原本应该从头到尾使用HTTPS加密会话的过程中混入了使用明文传输的HTTP会话一旦HTTP会话被劫持HTTPS会话就可能受到威胁 。SSLstrip 正是利用这一点通过劫持HTTP 会话劫持了SSL会话下图所示 SSLstrip 原理示意图。 下面具体阐述基于SSLstrip的SSL会话劫持流程阐述中依然以主机C为SSL客户端主机M为监测主机主机S为SSL服务端主机M通过ARP重定向技术使得主机C所有与外网的通信流都会从主机M处经过。 主机C向主机S的一个HTTPS页面发出一个HTTP请求主机M监听这个请求并转发给主机S。 主机S返回一个状态码为302的HTTP 响应报文报文消息头中Location头域以及消息实体中都给出了重定向网址形式分别为“Location: https://***.com/…”与“”。 主机M解析来自主机S的响应报文将其中所有的https替换成http指定主机M另一个未使用的端口为通信端口假设为8181端口并且记录修改过的url。需要做的替换包括消息头中的“Location: https://***.com/…”替换成“Location: http://***.com:8181/…”消息实体中链接“ a href”https://***.com/…””替换成“”。 主机C解析经过篡改后的HTTP响应报文经过重定向与主机M的8181端口通过HTTP方式建立了连接二者之间通信数据明文传输。 主机M冒充客户端与主机S建立HTTPS会话二者之间的通信数据通过密文传输但主机M可以自由地解密这些数据。 经过以上步骤主机M成功实现了主机CSSL客户端与主机SSSL服务端之间的会话劫持并可以对明文形式的会话内容进行监测。 2.2 成功的必要条件 这种类型的SSL会话劫持成功的必要条件如下 a 能够通过ARP欺骗、DNS欺骗或者浏览器数据重定向等欺骗技术使得SSL客户端和服务端S之间的数据都流向中间人监测主机b 客户端访问的Web页面存在http页面至https页面的跳转c SSL服务端未要求对SSL客户端进行认证。三、两种典型 SSL 会话劫持技术的对比小结 传统的基于伪造 X.509 证书的 SSL 会话劫持方式其最大的问题就在于客户端浏览器会弹出警告提示对话框这个提示是如此醒目以至于只要用户有一定的安全意识和网络知识劫持成功的概率就会大大降低。随着网络知识的慢慢普及这种技术的生存空间会越来越小。 基于 HTTP 与 HTTPS 之间跳转验证漏洞的 SSL 会话劫持方式是近几年新出的一种技术。在此种方式下客户端浏览器不会有任何不安全的警告或提示只是原先的HTTPS连接已经被HTTP连接所替换迷惑性大大增强。一般为了进一步加强欺骗效果监测主机还可以一个银色的“安全锁”图案显示在非安全的网址前面。但其缺陷也很明显一旦用户在浏览器地址栏的输入中指定使用HTTPS协议就会发现网页根本无法打开。因此只要用户养成良好的上网习惯这种方式的会话劫持就会失败。 安装 pycurl 安装命令 sudo apt-get install libcurl4-openssl-dev pip install pycurl 杂项 scrapy 了解 scrapy 已经做过的功能优化等。。。防止重复造轮子如去重编码检测dns缓存http长连接,gzip等等。 JS相关。 这个是被问的最多的。看具体情况解决。可模拟相关js执行、绕过或直接调浏览器去访问。自己用一个JS引擎模拟一个浏览器环境难度太大了参见V8的DEMO。 调浏览器有很多方法。难以细说关键字如下seleniumphantomjscasperjsghostwebkitscrapyjssplash。一些细节如关掉CSS渲染图片加载等。只有scrapyjs是完全异步的相对是速度最快的scrapyjs将webkit的事件循环和twisted的事件循环合在一起了。其他的方案要么阻塞要么用多进程。简单的js需求对效率要求不高随意选最优方案是scrapyjs定制webkit去掉不需要的功能。调浏览器开页面是比较耗资源的主要是cpu 内容解析。 对于页面解析最强大的当然是XPATH、css选择器、正则表达式这个对于不同网站不同的使用者都不一样就不用过多的说明附两个比较好的网址 正则表达式入门http://www.cnblogs.com/huxi/archive/2010/07/04/1771073.html 正则表达式在线测试http://tool.oschina.net/regex/ 其次就是解析库了常用的有两个lxml和BeautifulSoup对于这两个的使用介绍两个比较好的网站 lxmlhttp://my.oschina.net/jhao104/blog/639448 BeautifulSouphttp://cuiqingcai.com/1319.html 对于这两个库都是HTML/XML的处理库Beautifulsoup纯python实现效率低但是功能实用比如能用通过结果搜索获得某个HTML节点的源码lxmlC语言编码高效支持Xpath 机器学习不一定好用效果问题人工问题-需要训练。还有写些正则去模糊匹配。 新闻类似的正文提取有readability,boilerplate。 分布式。 首先考虑按任务目标切分然后让不同目标的爬虫在不同机器上跑 完全的对等分布式多爬虫爬一个目标把任务队列替换掉爬虫改改即可。github里面有几个现有的实现参考。 分布式需求可能是伪命题。想清楚为何要分布式。硬件够不够像什么拿一个不支持持久化的url队列的爬虫说量大需要分布式的我只能默念你为何这么吊。 部署调度 部署推荐scrapyd。这也是官方推荐的方法。 大量爬虫的调度这个目前13-10没有现成的合适方法期望是实现爬虫的某些配置放数据库提供web后台 然后按配置周期、定时运行爬虫终止暂停爬虫等等。可以实现但要自己写不少东西。 ip 限制问题 买的起大量ip的可买买大量同网段爬可能导致整网段被封。 找大量免费的开放http代理筛选可用的免费开放代理不可靠写个调度机制自动根据成功次数延迟等选择合适代理这个功能难以在scrapy内实现参考scrapinghub的crawlera我完成了一个本地版。 在开发爬虫过程中经常会遇到IP被封掉的情况这时就需要用到代理IP 在urllib2包中有ProxyHandler类通过此类可以设置代理访问网页如下代码片段 import urllib2proxy urllib2.ProxyHandler({http: 127.0.0.1:8087})opener urllib2.build_opener(proxy)urllib2.install_opener(opener)response urllib2.urlopen(http://www.baidu.com)print response.read()url 去重 如果有千万级的URL需要去重需要仔细看下scrapy的去重机制和bloom filter布隆过滤器。bloomfilter有个公式可以算需要多少内存。另bloomfilter scrapy在github有现有实现可以参考。 存储。 mongodbmongodb不满足某些功能时考虑hbase,参考http://blog.scrapinghub.com/2013/05/13/mongo-bad-for-scraped-data/ 硬件 硬件扛不住别玩爬虫。。。曾在I3 4G 1T上跑爬虫。卡在磁盘io量大磁盘io差内存低出现内存占用飙升。很难调试调试爬虫看实际跑耗时较长初步以为是爬虫有问题内存占用高导致数据库卡。调试结果确认为配置低量太大导致数据库慢数据库慢之后爬虫任务队列占满内存并开始写磁盘又循环导致数据库慢。 爬虫监控 scrapyd自带简单的监控不够的话用scrapy的webservice自己写 如何防止死循环 在 Scrapy 的默认配置中是根据 url 进行去重的。这个对付一般网站是够的。但是有一些网站的 SEO 做的很变态为了让爬虫多抓会根据 request动态的生成一些链接导致爬虫 在网站上抓取大量的随机页面甚至是死循环。。 为了解决这个问题有2个方案 (1) 在 setting.py 中设定爬虫的嵌套次数上限(全局设定实际是通过 DepthMiddleware 实现的) DEPTH_LIMIT 20(2) 在 parse 中通过读取 response 来自行判断( spider级别设定 ) def parse(self, response):if response.meta[depth] 100:print Loop? 学习爬虫的正确打开方式 看了大部分回答不禁叹口气主要是因为看到很多大牛在回答像  如何入门爬虫  这种问题的时候一如当年学霸讲解题目跳步无数然后留下一句   不就是这样推嘛 让一众小白菜鸟一脸懵逼。。作为一个0起步之前连python都不会目前总算掌握基础开始向上进阶的菜鸟深知其中的不易所以我会在这个回答里尽可能全面、细节地分享给大家从0学习爬虫的各种步骤如果对你有帮助请点赞~ 首先你要对爬虫有个明确的认识。。。 在战略上藐视 “所有网站皆可爬”互联网的内容都是人写出来的而且都是偷懒写出来的不会第一页是a下一页是8所以肯定有规律这就给人有了爬取的可能可以说天下没有不能爬的网站 “框架不变”网站不同但是原理都类似大部分爬虫都是从 发送请求——获得页面——解析页面——下载内容——储存内容 这样的流程来进行只是用的工具不同 在战术上重视 持之以恒戒骄戒躁对于初学入门不可轻易自满以为爬了一点内容就什么都会爬了爬虫虽然是比较简单的技术但是往深学也是没有止境的比如搜索引擎等只有不断尝试刻苦钻研才是王道为何有种小学作文即视感 然后你需要一个宏伟的目标来让你有持续学习的动力没有实操项目真的很难有动力 我要爬整个豆瓣... 我要爬整个草什么榴社区我要爬知乎各种妹子的联系方式*^#%^$# 接着你需要扪心自问一下自己的 python 基本功吼不吼啊 吼啊——OK开始欢快地学习爬虫吧 不吼你还需要学习一个赶紧回去看Python核心编程教程。至少这些功能和语法你要有基本的掌握 listdict用来序列化你爬的东西 切片用来对爬取的内容进行分割生成 条件判断if等用来解决爬虫过程中哪些要哪些不要的问题 循环和迭代for while 用来循环重复爬虫动作 文件读写操作用来读取参数、保存爬下来的内容等 然后你需要补充一下下面几个内容作为你的知识储备 注这里并非要求“掌握”下面讲的两点只需要先了解然后通过具体项目来不断实践直到熟练掌握 1、网页的基本知识 基本的HTML语言知识知道href等大学计算机一级内容即可 理解网站的发包和收包的概念POST GET 稍微一点点的js知识用于理解动态网页当然如果本身就懂当然更好啦 2、一些分析语言为接下来解析网页内容做准备 NO.1 正则表达式扛把子技术总得会最基础的 NO.2 XPATH高效的分析语言表达清晰简单掌握了以后基本可以不用正则 参考XPath 教程[http://link.zhihu.com/?targethttp%3A//www.w3school.com.cn/xpath/] NO.3 Beautifulsoup 美丽汤模块解析网页神器,一款神器如果不用一些爬虫框架如后文讲到的scrapy配合requesturllib等模块后面会详细讲可以编写各种小巧精干的爬虫脚本 官网文档Beautiful Soup 4.2.0 文档[http://link.zhihu.com/?targethttp%3A//beautifulsoup.readthedocs.org/zh_CN/latest/] 参考案例 接着你需要一些高效的工具来辅助 同样这里先了解到具体的项目的时候再熟悉运用 NO.1 F12 开发者工具 看源代码快速定位元素 分析xpath1、此处建议谷歌系浏览器,可以在源码界面直接右键看 NO.2 抓包工具 推荐httpfox火狐浏览器下的插件,比谷歌火狐系自带的F12工具都要好可以方便查看网站收包发包的信息 NO.3 XPATH CHECKER (火狐插件 非常不错的 xpath 测试工具但是有几个坑都是个人踩过的在此告诫大家 1、xpath checker 生成的是绝对路径遇到一些动态生成的图标常见的有列表翻页按钮等飘忽不定的绝对路径很有可能造成错误所以这里建议在真正分析的时候只是作为参考2、记得把如下图 xpath 框里的“x:”去掉貌似这个是早期版本xpath的语法目前已经和一些模块不兼容比如scrapy还是删去避免报错 NO.4 正则表达测试工具 在线正则表达式测试(http://link.zhihu.com/?targethttp%3A//tool.oschina.net/regex/) 拿来多练练手也辅助分析里面有很多现成的正则表达式可以用也可以进行参考 ok这些你都基本有一些了解了现在开始进入抓取时间上各种模块吧python 的火很大原因就是各种好用的模块这些模块是居家旅行爬网站常备的—— urllib urllib2 requests**不想重复造轮子有没有现成的框架 华丽丽的scrapy(这块我会重点讲我的最爱** 遇到动态页面怎么办 selenium会了这个配合 scrapy 无往不利是居家旅行爬网站又一神器 爬来的东西怎么用 pandas基于 numpy 的数据分析模块相信我如果你不是专门搞 TB 级数据的这个就够了 然后是数据库这里我认为开始并不需要非常深入在需要的时候再学习即可 mysql mongodb sqllite遇到反爬虫策略验证码之类咋整 PIL opencv pybrain进阶技术 多线程、分布式 Python 网页爬虫 文本处理 科学计算 机器学习 数据挖掘兵器谱 曾经因为NLTK的缘故开始学习Python之后渐渐成为我工作中的第一辅助脚本语言虽然开发语言是C/C但平时的很多文本数据处理任务都交给了Python。离开腾讯创业后第一个作品课程图谱也是选择了Python系的Flask框架渐渐的将自己的绝大部分工作交给了Python。这些年来接触和使用了很多Python工具包特别是在文本处理科学计算机器学习和数据挖掘领域有很多很多优秀的Python工具包可供使用所以作为Pythoner也是相当幸福的。其实如果仔细留意微博你会发现很多这方面的分享自己也Google了一下发现也有同学总结了“Python机器学习库”不过总感觉缺少点什么。最近流行一个词全栈工程师full stack engineer作为一个苦逼的创业者天然的要把自己打造成一个full stack engineer而这个过程中这些Python工具包给自己提供了足够的火力所以想起了这个系列。当然这也仅仅是抛砖引玉希望大家能提供更多的线索来汇总整理一套Python网页爬虫文本处理科学计算机器学习和数据挖掘的兵器谱。 一、Python网页爬虫工具集 一个真实的项目一定是从获取数据开始的。无论文本处理机器学习和数据挖掘都需要数据除了通过一些渠道购买或者下载的专业数据外常常需要大家自己动手爬数据这个时候爬虫就显得格外重要了幸好Python提供了一批很不错的网页爬虫工具框架既能爬取数据也能获取和清洗数据我们也就从这里开始了 1. Scrapy Scrapy, a fast high-level screen scraping and web crawling framework for Python. 鼎鼎大名的Scrapy相信不少同学都有耳闻课程图谱中的很多课程都是依靠Scrapy抓去的这方面的介绍文章有很多推荐大牛pluskid早年的一篇文章《Scrapy 轻松定制网络爬虫》历久弥新。 官方主页http://scrapy.org/ Github代码页: https://github.com/scrapy/scrapy 2. Beautiful Soup You didn’t write that awful page. You’re just trying to get some data out of it. Beautiful Soup is here to help. Since 2004, it’s been saving programmers hours or days of work on quick-turnaround screen scraping projects. 读书的时候通过《集体智慧编程》这本书知道Beautiful Soup的后来也偶尔会用用非常棒的一套工具。客观的说Beautifu Soup不完全是一套爬虫工具需要配合urllib使用而是一套HTML/XML数据分析清洗和获取工具。 官方主页http://www.crummy.com/software/BeautifulSoup/ 3. Python-Goose Html Content / Article Extractor, web scrapping lib in Python Goose最早是用Java写得后来用Scala重写是一个Scala项目。Python-Goose用Python重写依赖了Beautiful Soup。前段时间用过感觉很不错给定一个文章的URL, 获取文章的标题和内容很方便。 Github主页https://github.com/grangier/python-goose 二、Python文本处理工具集 从网页上获取文本数据之后依据任务的不同就需要进行基本的文本处理了譬如对于英文来说需要基本的tokenize对于中文则需要常见的中文分词进一步的话无论英文中文还可以词性标注句法分析关键词提取文本分类情感分析等等。这个方面特别是面向英文领域有很多优秀的工具包我们一一道来。 1. NLTK — Natural Language Toolkit NLTK is a leading platform for building Python programs to work with human language data. It provides easy-to-use interfaces to over 50 corpora and lexical resources such as WordNet, along with a suite of text processing libraries for classification, tokenization, stemming, tagging, parsing, and semantic reasoning, and an active discussion forum. 搞自然语言处理的同学应该没有人不知道NLTK吧这里也就不多说了。不过推荐两本书籍给刚刚接触NLTK或者需要详细了解NLTK的同学: 一个是官方的《Natural Language Processing with Python》以介绍NLTK里的功能用法为主同时附带一些Python知识同时国内陈涛同学友情翻译了一个中文版这里可以看到推荐《用Python进行自然语言处理》中文翻译-NLTK配套书另外一本是《Python Text Processing with NLTK 2.0 Cookbook》这本书要深入一些会涉及到NLTK的代码结构同时会介绍如何定制自己的语料和模型等相当不错。 官方主页http://www.nltk.org/ Github代码页https://github.com/nltk/nltk 2. Pattern Pattern is a web mining module for the Python programming language. It has tools for data mining (Google, Twitter and Wikipedia API, a web crawler, a HTML DOM parser), natural language processing (part-of-speech taggers, n-gram search, sentiment analysis, WordNet), machine learning (vector space model, clustering, SVM), network analysis and canvas visualization. Pattern由比利时安特卫普大学CLiPS实验室出品客观的说Pattern不仅仅是一套文本处理工具它更是一套web数据挖掘工具囊括了数据抓取模块包括Google, Twitter, 维基百科的API以及爬虫和HTML分析器文本处理模块词性标注情感分析等机器学习模块(VSM, 聚类SVM以及可视化模块等可以说Pattern的这一整套逻辑也是这篇文章的组织逻辑不过这里我们暂且把Pattern放到文本处理部分。我个人主要使用的是它的英文处理模块Pattern.en, 有很多很不错的文本处理功能包括基础的tokenize, 词性标注句子切分语法检查拼写纠错情感分析句法分析等相当不错。 官方主页http://www.clips.ua.ac.be/pattern 3. TextBlob: Simplified Text Processing TextBlob is a Python (2 and 3) library for processing textual data. It provides a simple API for diving into common natural language processing (NLP) tasks such as part-of-speech tagging, noun phrase extraction, sentiment analysis, classification, translation, and more. TextBlob是一个很有意思的Python文本处理工具包它其实是基于上面两个Python工具包NLKT和Pattern做了封装TextBlob stands on the giant shoulders of NLTK and pattern, and plays nicely with both同时提供了很多文本处理功能的接口包括词性标注名词短语提取情感分析文本分类拼写检查等甚至包括翻译和语言检测不过这个是基于Google的API的有调用次数限制。TextBlob相对比较年轻有兴趣的同学可以关注。 官方主页http://textblob.readthedocs.org/en/dev/ Github代码页https://github.com/sloria/textblob 4. MBSP for Python MBSP is a text analysis system based on the TiMBL and MBT memory based learning applications developed at CLiPS and ILK. It provides tools for Tokenization and Sentence Splitting, Part of Speech Tagging, Chunking, Lemmatization, Relation Finding and Prepositional Phrase Attachment. MBSP与Pattern同源同出自比利时安特卫普大学CLiPS实验室提供了Word Tokenization, 句子切分词性标注Chunking, Lemmatization句法分析等基本的文本处理功能感兴趣的同学可以关注。 官方主页http://www.clips.ua.ac.be/pages/MBSP 5. Gensim: Topic modeling for humans Gensim是一个相当专业的主题模型Python工具包无论是代码还是文档我们曾经用《如何计算两个文档的相似度》介绍过Gensim的安装和使用过程这里就不多说了。 官方主页http://radimrehurek.com/gensim/index.html github代码页https://github.com/piskvorky/gensim 6. langid.py: Stand-alone language identification system 语言检测是一个很有意思的话题不过相对比较成熟这方面的解决方案很多也有很多不错的开源工具包不过对于Python来说我使用过langid这个工具包也非常愿意推荐它。langid目前支持97种语言的检测提供了很多易用的功能包括可以启动一个建议的server通过json调用其API可定制训练自己的语言检测模型等可以说是“麻雀虽小五脏俱全”。 Github主页https://github.com/saffsd/langid.py 7. Jieba: 结巴中文分词 “结巴”中文分词做最好的Python中文分词组件 “Jieba” (Chinese for “to stutter”) Chinese text segmentation: built to be the best Python Chinese word segmentation module. 好了终于可以说一个国内的Python文本处理工具包了结巴分词其功能包括支持三种分词模式精确模式、全模式、搜索引擎模式支持繁体分词支持自定义词典等是目前一个非常不错的Python中文分词解决方案。 Github主页https://github.com/fxsjy/jieba 8. xTAS xtas, the eXtensible Text Analysis Suite, a distributed text analysis package based on Celery and Elasticsearch. 感谢微博朋友 大山坡的春 提供的线索我们组同事之前发布了xTAS也是基于python的text mining工具包欢迎使用链接http://t.cn/RPbEZOW。看起来很不错的样子回头试用一下。 Github代码页https://github.com/NLeSC/xtas 三、Python 科学计算工具包 说起科学计算大家首先想起的是 Matlab集数值计算可视化工具及交互于一身不过可惜是一个商业产品。开源方面除了GNU Octave在尝试做一个类似Matlab的工具包外Python的这几个工具包集合到一起也可以替代Matlab的相应功能NumPySciPyMatplotlibiPython。同时这几个工具包特别是NumPy和SciPy也是很多Python文本处理 机器学习 数据挖掘工具包的基础非常重要。最后再推荐一个系列《用Python做科学计算》将会涉及到NumPy, SciPy, Matplotlib可以做参考。 1. NumPy NumPy is the fundamental package for scientific computing with Python. It contains among other things: 1a powerful N-dimensional array object 2sophisticated (broadcasting) functions 3tools for integrating C/C and Fortran code 4 useful linear algebra, Fourier transform, and random number capabilities Besides its obvious scientific uses, NumPy can also be used as an efficient multi-dimensional container of generic data. Arbitrary data-types can be defined. This allows NumPy to seamlessly and speedily integrate with a wide variety of databases. NumPy几乎是一个无法回避的科学计算工具包最常用的也许是它的N维数组对象其他还包括一些成熟的函数库用于整合C/C和Fortran代码的工具包线性代数、傅里叶变换和随机数生成函数等。NumPy提供了两种基本的对象ndarrayN-dimensional array object和 ufuncuniversal function object。ndarray是存储单一数据类型的多维数组而ufunc则是能够对数组进行处理的函数。 官方主页http://www.numpy.org/ 2. SciPyScientific Computing Tools for Python SciPy refers to several related but distinct entities: 1The SciPy Stack, a collection of open source software for scientific computing in Python, and particularly a specified set of core packages. 2The community of people who use and develop this stack. 3Several conferences dedicated to scientific computing in Python – SciPy, EuroSciPy and SciPy.in. 4The SciPy library, one component of the SciPy stack, providing many numerical routines. “SciPy是一个开源的Python算法库和数学工具包SciPy包含的模块有最优化、线性代数、积分、插值、特殊函数、快速傅里叶变换、信号处理和图像处理、常微分方程求解和其他科学与工程中常用的计算。其功能与软件MATLAB、Scilab和GNU Octave类似。 Numpy和Scipy常常结合着使用Python大多数机器学习库都依赖于这两个模块。”—-引用自“Python机器学习库” 官方主页http://www.scipy.org/ 3. Matplotlib matplotlib is a python 2D plotting library which produces publication quality figures in a variety of hardcopy formats and interactive environments across platforms. matplotlib can be used in python scripts, the python and ipython shell (ala MATLAB®* or Mathematica®†), web application servers, and six graphical user interface toolkits. matplotlib 是python最著名的绘图库它提供了一整套和matlab相似的命令API十分适合交互式地进行制图。而且也可以方便地将它作为绘图控件嵌入GUI应用程序中。Matplotlib可以配合ipython shell使用提供不亚于Matlab的绘图体验总之用过了都说好。 官方主页http://matplotlib.org/ 4. iPython IPython provides a rich architecture for interactive computing with: 1Powerful interactive shells (terminal and Qt-based). 2A browser-based notebook with support for code, text, mathematical expressions, inline plots and other rich media. 3Support for interactive data visualization and use of GUI toolkits. 4Flexible, embeddable interpreters to load into your own projects. 5Easy to use, high performance tools for parallel computing. “iPython 是一个Python 的交互式Shell比默认的Python Shell 好用得多功能也更强大。 她支持语法高亮、自动完成、代码调试、对象自省支持 Bash Shell 命令内置了许多很有用的功能和函式等非常容易使用。 ” 启动iPython的时候用这个命令“ipython –pylab”默认开启了matploblib的绘图交互用起来很方便。 官方主页http://ipython.org/ 四、Python 机器学习 数据挖掘 工具包 机器学习和数据挖掘这两个概念不太好区分这里就放到一起了。这方面的开源Python工具包有很多这里先从熟悉的讲起再补充其他来源的资料也欢迎大家补充。 1. scikit-learn: Machine Learning in Python scikit-learn (formerly scikits.learn) is an open source machine learning library for the Python programming language. It features various classification, regression and clustering algorithms including support vector machines, logistic regression, naive Bayes, random forests, gradient boosting, k-means and DBSCAN, and is designed to interoperate with the Python numerical and scientific libraries NumPy and SciPy. 首先推荐大名鼎鼎的scikit-learnscikit-learn是一个基于NumPy, SciPy, Matplotlib的开源机器学习工具包主要涵盖分类回归和聚类算法例如SVM 逻辑回归朴素贝叶斯随机森林k-means等算法代码和文档都非常不错在许多Python项目中都有应用。例如在我们熟悉的NLTK中分类器方面就有专门针对scikit-learn的接口可以调用scikit-learn的分类算法以及训练数据来训练分类器模型。这里推荐一个视频也是我早期遇到scikit-learn的时候推荐过的推荐一个Python机器学习工具包Scikit-learn以及相关视频–Tutorial: scikit-learn – Machine Learning in Python 官方主页http://scikit-learn.org/ 2. Pandas: Python Data Analysis Library Pandas is a software library written for the Python programming language for data manipulation and analysis. In particular, it offers data structures and operations for manipulating numerical tables and time series. 第一次接触Pandas是由于Udacity上的一门数据分析课程“Introduction to Data Science” 的Project需要用Pandas库所以学习了一下Pandas。Pandas也是基于NumPy和Matplotlib开发的主要用于数据分析和数据可视化它的数据结构DataFrame和R语言里的data.frame很像特别是对于时间序列数据有自己的一套分析机制非常不错。这里推荐一本书《Python for Data Analysis》作者是Pandas的主力开发依次介绍了iPython, NumPy, Pandas里的相关功能数据可视化数据清洗和加工时间数据处理等案例包括金融股票数据挖掘等相当不错。 官方主页http://pandas.pydata.org/ 分割线以上工具包基本上都是自己用过的以下来源于其他同学的线索特别是《Python机器学习库》《23个python的机器学习包》做了一点增删修改欢迎大家补充 3. mlpy – Machine Learning Python mlpy is a Python module for Machine Learning built on top of NumPy/SciPy and the GNU Scientific Libraries. mlpy provides a wide range of state-of-the-art machine learning methods for supervised and unsupervised problems and it is aimed at finding a reasonable compromise among modularity, maintainability, reproducibility, usability and efficiency. mlpy is multiplatform, it works with Python 2 and 3 and it is Open Source, distributed under the GNU General Public License version 3. 官方主页http://mlpy.sourceforge.net/ 4. MDPThe Modular toolkit for Data Processing Modular toolkit for Data Processing (MDP) is a Python data processing framework. From the user’s perspective, MDP is a collection of supervised and unsupervised learning algorithms and other data processing units that can be combined into data processing sequences and more complex feed-forward network architectures. From the scientific developer’s perspective, MDP is a modular framework, which can easily be expanded. The implementation of new algorithms is easy and intuitive. The new implemented units are then automatically integrated with the rest of the library. The base of available algorithms is steadily increasing and includes signal processing methods (Principal Component Analysis, Independent Component Analysis, Slow Feature Analysis), manifold learning methods ([Hessian] Locally Linear Embedding), several classifiers, probabilistic methods (Factor Analysis, RBM), data pre-processing methods, and many others. “MDP用于数据处理的模块化工具包一个Python数据处理框架。 从用户的观点MDP是能够被整合到数据处理序列和更复杂的前馈网络结构的一批监督学习和非监督学习算法和其他数据处理单元。计算依照速度和内存需求而高效的执行。从科学开发者的观点MDP是一个模块框架它能够被容易地扩展。新算法的实现是容易且直观的。新实现的单元然后被自动地与程序库的其余部件进行整合。MDP在神经科学的理论研究背景下被编写但是它已经被设计为在使用可训练数据处理算法的任何情况中都是有用的。其站在用户一边的简单性各种不同的随时可用的算法及应用单元的可重用性使得它也是一个有用的教学工具。” 官方主页http://mdp-toolkit.sourceforge.net/ 5. PyBrain PyBrain is a modular Machine Learning Library for Python. Its goal is to offer flexible, easy-to-use yet still powerful algorithms for Machine Learning Tasks and a variety of predefined environments to test and compare your algorithms. PyBrain is short for Python-Based Reinforcement Learning, Artificial Intelligence and Neural Network Library. In fact, we came up with the name first and later reverse-engineered this quite descriptive “Backronym”. “PyBrain(Python-Based Reinforcement Learning, Artificial Intelligence and Neural Network)是Python的一个机器学习模块它的目标是为机器学习任务提供灵活、易应、强大的机器学习算法。这名字很霸气 PyBrain正如其名包括神经网络、强化学习(及二者结合)、无监督学习、进化算法。因为目前的许多问题需要处理连续态和行为空间必须使用函数逼近(如神经网络)以应对高维数据。PyBrain以神经网络为核心所有的训练方法都以神经网络为一个实例。” 官方主页http://www.pybrain.org/ 6. PyML – machine learning in Python PyML is an interactive object oriented framework for machine learning written in Python. PyML focuses on SVMs and other kernel methods. It is supported on Linux and Mac OS X. “PyML是一个Python机器学习工具包为各分类和回归方法提供灵活的架构。它主要提供特征选择、模型选择、组合分类器、分类评估等功能。” 项目主页http://pyml.sourceforge.net/ 7. MilkMachine learning toolkit in Python. Its focus is on supervised classification with several classifiers available: SVMs (based on libsvm), k-NN, random forests, decision trees. It also performs feature selection. These classifiers can be combined in many ways to form different classification systems. “Milk是Python的一个机器学习工具箱其重点是提供监督分类法与几种有效的分类分析SVMs(基于libsvm)K-NN随机森林经济和决策树。它还可以进行特征选择。这些分类可以在许多方面相结合形成不同的分类系统。对于无监督学习它提供K-means和affinity propagation聚类算法。” 官方主页http://luispedro.org/software/milk http://luispedro.org/software/milk 8. PyMVPA: MultiVariate Pattern Analysis (MVPA) in Python PyMVPA is a Python package intended to ease statistical learning analyses of large datasets. It offers an extensible framework with a high-level interface to a broad range of algorithms for classification, regression, feature selection, data import and export. It is designed to integrate well with related software packages, such as scikit-learn, and MDP. While it is not limited to the neuroimaging domain, it is eminently suited for such datasets. PyMVPA is free software and requires nothing but free-software to run. “PyMVPA(Multivariate Pattern Analysis in Python)是为大数据集提供统计学习分析的Python工具包它提供了一个灵活可扩展的框架。它提供的功能有分类、回归、特征选择、数据导入导出、可视化等” 官方主页http://www.pymvpa.org/ 9. Pyrallel – Parallel Data Analytics in Python Experimental project to investigate distributed computation patterns for machine learning and other semi-interactive data analytics tasks. “Pyrallel(Parallel Data Analytics in Python)基于分布式计算模式的机器学习和半交互式的试验项目可在小型集群上运行” Github代码页http://github.com/pydata/pyrallel 10. Monte – gradient based learning in Python Monte (python) is a Python framework for building gradient based learning machines, like neural networks, conditional random fields, logistic regression, etc. Monte contains modules (that hold parameters, a cost-function and a gradient-function) and trainers (that can adapt a module’s parameters by minimizing its cost-function on training data). Modules are usually composed of other modules, which can in turn contain other modules, etc. Gradients of decomposable systems like these can be computed with back-propagation. “Monte (machine learning in pure Python)是一个纯Python机器学习库。它可以迅速构建神经网络、条件随机场、逻辑回归等模型使用inline-C优化极易使用和扩展。” 官方主页http://montepython.sourceforge.net 11. Theano Theano is a Python library that allows you to define, optimize, and evaluate mathematical expressions involving multi-dimensional arrays efficiently. Theano features: 1tight integration with NumPy – Use numpy.ndarray in Theano-compiled functions. 2transparent use of a GPU – Perform data-intensive calculations up to 140x faster than with CPU.(float32 only) 3efficient symbolic differentiation – Theano does your derivatives for function with one or many inputs. 4speed and stability optimizations – Get the right answer for log(1x) even when x is really tiny. 5dynamic C code generation – Evaluate expressions faster. 6 extensive unit-testing and self-verification – Detect and diagnose many types of mistake. Theano has been powering large-scale computationally intensive scientific investigations since 2007. But it is also approachable enough to be used in the classroom (IFT6266 at the University of Montreal). “Theano 是一个 Python 库用来定义、优化和模拟数学表达式计算用于高效的解决多维数组的计算问题。Theano的特点紧密集成Numpy高效的数据密集型GPU计算高效的符号微分运算高速和稳定的优化动态生成c代码广泛的单元测试和自我验证。自2007年以来Theano已被广泛应用于科学运算。theano使得构建深度学习模型更加容易可以快速实现多种模型。PSTheano一位希腊美女Croton最有权势的Milo的女儿后来成为了毕达哥拉斯的老婆。” 12. Pylearn2 Pylearn2 is a machine learning library. Most of its functionality is built on top of Theano. This means you can write Pylearn2 plugins (new models, algorithms, etc) using mathematical expressions, and theano will optimize and stabilize those expressions for you, and compile them to a backend of your choice (CPU or GPU). “Pylearn2建立在theano上部分依赖scikit-learn上目前Pylearn2正处于开发中将可以处理向量、图像、视频等数据提供MLP、RBM、SDA等深度学习模型。”
http://www.huolong8.cn/news/245944/

相关文章:

  • 做网站视频网站用别人的电影网站做公众号
  • 建网站和建网店的区别毕业季网站如何做网页
  • 网站修改标题有影响吗便宜的广州网站建设服务
  • 网站建设新闻发布注意中国房地产排名100强
  • 提升型企业网络营销网站网络营销的特点包括超前性
  • 个人网站设计模板中文wordpress category模板
  • 平台网站推广方案wordpress外链产品
  • ftps 网站怎么做建设银行舟山分行网站
  • 网站群建设成本分析共享充电宝app开发
  • 中山网站只设计电商网站设计案例
  • 服装网站建设2345网址导航是什么浏览器
  • 公司怎么做网站需要多少钱上海网站开发
  • 呼和浩特腾讯企业邮箱邯郸seo排名
  • 廊坊做网站公司排名企业微信公众号平台官网
  • 西安网站开发哪家好高端品牌网站建设公司哪家好
  • vs2010网站开发登录代码深圳智加设计公司
  • 网站开发 工资高吗福州网站制作建设
  • 网站平台塘厦高铁站
  • 网站模板怎么修改怎么做网站赚钱吗
  • app排版网站网站站长是什么
  • 网站已运行时间代码网站seo哪家公司好
  • 创建网站的向导和模板网站开发有哪些软件
  • 大沥网站制作网络营销的目的是
  • 网站备案后经营江门网站优化排名
  • seo 网站制作中国十大传媒公司排名
  • 湖南建设集团网站手机wap版
  • 北京专业网站制作介绍wordpress go跳转页
  • 网站建设基础知识及专业术语被k掉的网站怎么做才能有收录
  • 外贸网站推广平台蓝颜seo牛四川营销型网站建设
  • 关键词爱站网医联媒体网站建设