一、进程、线程、协成

  1、进程、线程、协成之间的关系
           1、  线程是计算机中最小的工作单元。
              2、 进程是提供资源供n个线程使用,即进程是最小的管理单元。

      3、协程是人为控制的线程。

      4、总结:1、python中由于有 GIL锁的存在,所以一个进程中同一时刻只有一个线程被CPU调度,所以在计算密集型,使用多进程而在io密集型使用多线程。

         2、使用协成可以实现单线程下的并发,线程中cpu在遇到io操作时就会切到下一个线程中,这样大大的影响的效率于是人为的控制cpu在线程中的切换,当cpu在线程中遇到io会切换到该线程的下一个程序中这就是协成

  2、异步非阻塞模块

   1、gevent模块,基于协程的异步非阻塞模块。
           2、Twisted,基于事件驱动(while循环检测)异步非阻塞模块(框架)。
           3、非阻塞是指不等待 ,异步是指回调,执行某个任务完成之后,自动执行的函数。回调函数

二、scarpy框架

  1、重写scrapy请求头方法

# -*- coding: utf-8 -*-
import scrapy
from scrapy.http import Request
from scrapy.selector import HtmlXPathSelector #response= HtmlXPathSelector(response)主要是在parse函数中使用,
from urllib.parse import urlencode
from ..items import MyscrapyItem
class BaiduSpider(scrapy.Spider):
name = 'baidu' #爬虫应用的名称,通过此名称启动爬虫命令
allowed_domains = ['www.amazon.cn'] # 允许爬取数据的域名
def __init__(self,keywords=None,*args,**kwargs):
super(BaiduSpider,self).__init__(*args,**kwargs)
self.keywords=keywords #主要是接受一些外部传进来的参数
def start_requests(self): #重写scrapy请求头url必须写这个名字的函数
url='https://www.amazon.cn/s/ref=nb_sb_noss_1?' #新url
parmas={
'field-keywords':self.keywords #主要是定义一些外部传进来的参数
}
url=url+urlencode(parmas,encoding='utf-8') #路径拼接,形成一个完整的url路径
yield Request(url,callback=self.parse_index) #yield返回数据给回调函数,也可以是return+[]的方式返回数据给回调函数,yield返回的是生成器,return+[]返回的可迭代对象
# return [Request(url='www.baidu.com',callback=self.parse),] def parse_index(self, response):
urls=response.xpath('//*[contains(@id,"result_"]/div/div[3]/div[1]/a/@href').extract()
for url in urls:
print(url)
yield Request(url,callback=self.parse) #返回详情页的信息
next_url=response.urljoin(response.xpath('//*[@id="pagnNextLink"]/@href').extract_first())
yield Request(next_url,callback=self.parse_index) #返回下一页的url路径,返回的是个Request对象
def parse(self, response):
price=response.xpath('//*[@id="priceblock_ourprice"]/text()').extract_first().strip()
colour=response.xpath('//*[@id="variation_color_name"]/div/span/text()').extract_first().strip()
item=MyscrapyItem()
item['price']=price
item['colour']=colour
return item #返回的是个item对象
     或者是这种格式,只要返回的是个item对象及格
     obj = XiaoHuarItem(price=price, colour=colour, )
     yield obj

  2、items文件写法

import scrapy
class MyscrapyItem(scrapy.Item):
price=scrapy.Field()
colour=scrapy.Field()

  3、自定义pipelines文件

from scrapy.exceptions import DropItem    #主动触发异常用的
class CustomPipeline(object):
def __init__(self,val):
self.vale = val #构造一个对象特有的方法
def process_item(self, item, spider): #用于存储爬取的数据,可以存储在文件也可以存储在数据库。   f=opne('item.log','a+')
     f.write(item.price,item.colour)
     f.close()
return item # return表示会被后续的pipeline继续处理,因为有可以一个爬虫项目会有多个爬虫程序一起执行,但是都有写入同一个文件中,那就让第一个文件写入,其余后面的文件不用重复写入。 # raise DropItem() # 表示将item丢弃,不会被后续pipeline处理
    # if spider.name='baidu': #这就表示该文件只是存储这个名字的爬虫爬取的数据
      #f=opne('item.log','a+')
      #f.write(item.price,item.colour)
      #f.close()
    #return item
@classmethod
def from_crawler(cls, crawler):#初始化时候,用于创建pipeline对象,crawler这个类可以得到settings配置文件内的数据,如果需要给pipeline对象创建某个额外的参数就可以用这中方法
val = crawler.settings.getint('MMMM') #val = crawler.settings.get('MMMM') 读取配置文件的某个信息
return cls(val) def open_spider(self,spider): #在爬虫程序开始执行之前调用该方法
print('000000') def close_spider(self,spider): #在爬虫程序关闭后调用该方法
print('111111') 总结:这五个方法的执行顺序: 先执行from_crawler方法,用于初始化数据的时候读取配置文件,然后再执行爬虫程序的__init__方法,然后程序启动前执行open_spider方法,程序结束前保存数据时执行process_item方法,程序结果后
执行close_spider方法。

  4、自定义url去重功能

scrapy默认使用 scrapy.dupefilter.RFPDupeFilter 进行去重,settings相关配置有: 
DUPEFILTER_CLASS = 'scrapy.dupefilter.RFPDupeFilter' #去重文件,可以自定义
DUPEFILTER_DEBUG = False #默认去重功能是关闭的可以在settings中打开去重功能也可以在爬虫程序中手动指定去重 yield Request(url,callback=self.parse,dont_filter=True)
JOBDIR = "保存范文记录的日志路径,如:/root/" # 最终路径为 /root/requests.seen 默认url是存放在内存中的,只要添加上jobdir就可以吧url存放在指定文件中

  自己写一个去重规则

class RepeatUrl:
def __init__(self):
self.visited_url = set() #默认是一个集合,也可以是自定义链接一个数据库,文件等 @classmethod
def from_settings(cls, settings):
"""
初始化时,调用
"""
return cls() def request_seen(self, request):
"""
检测当前请求是否已经被访问过
:param request:
:return: True表示已经访问过;False表示未访问过
"""
if request.url in self.visited_url:
return True
self.visited_url.add(request.url)
return False def open(self):
"""
开始爬去请求时,调用
:return:
"""
print('open replication') def close(self, reason):
"""
结束爬虫爬取时,调用
:param reason:
:return:
"""
print('close replication') def log(self, request, spider):
"""
记录日志
:param request:
:param spider:
:return:
"""
print('repeat', request.url)
注意:写好自定义的去重规则后要将该文件设置到settings中该规程才能生效 比如:DUPEFILTER_CLASS = 'scrapy.dupefilter.RFPDupeFilter'

  5、自定义命令

   #自定制一键启动所有爬虫命令 
  from scrapy.commands import ScrapyCommand
from scrapy.utils.project import get_project_settings class Command(ScrapyCommand):
requires_project = True def syntax(self):
return '[options]' def short_desc(self):
return 'Runs all of the spiders' def run(self, args, opts): #这是源码的入口
spider_list = self.crawler_process.spiders.list()
for name in spider_list: #循环所有的爬虫程序名称
self.crawler_process.crawl(name, **opts.__dict__) #准备所有的爬虫程序
self.crawler_process.start() #开始爬取任务
注意:1、在spiders同级创建任意目录,如:commands
   2、在其中创建 crawlall.py 文件 (此处文件名就是自定义的命令)
   3、在settings.py 中添加配置 COMMANDS_MODULE = '项目名称.目录名称'
   4、在项目目录执行命令:scrapy crawlall
  
  #自定制在py文件中启动某个爬虫命令  
  from scrapy.cmdline import execute  
  execute(['scrapy', '命令', '爬虫程序名称','-a','传入的参数'])
  eg:execute(['scrapy', 'crawl', 'baidu','-a','keywords=iphone7'])
注意:自定制的py文件名称必须是entrypoint.py

    6、自定义信号

from scrapy import signals
class MyExtension(object):
def __init__(self, value):
self.value = value #定义自己想要的方法 @classmethod
def from_crawler(cls, crawler): #扩展功能,在扩展功能里注册信号
val = crawler.settings.getint('MMMM')#读取配置文件信息
ext = cls(val)
crawler.signals.connect(ext.spider_opened, signal=signals.spider_opened) #注册信号
crawler.signals.connect(ext.spider_closed, signal=signals.spider_closed) #注册信号,可以注册很多信号,看源码
return ext #如果不需要扩展功能那么就直接注册信号即可 def spider_opened(self, spider): #爬虫程序启动时触发的信号
print('open') def spider_closed(self, spider): #爬虫程序关闭时触发的信号
print('close')
注释:1、在项目目录下创建一个py文件,将自定义的信号写入该文件,建议py文件名为extensions
   2、在settings中注册自定义信号的文件
    eg:EXTENSIONS = {'scrapy.extensions.telnet.TelnetConsole': 300,}

   7、中间件

#下载中间件
class DownMiddleware1(object):
def process_request(self, request, spider): #请求过去的中间件带的时request
"""
请求需要被下载时,经过所有下载器中间件的process_request调用
return:
None,继续后续中间件去下载,默认就是什么都不返回;
Response对象,停止process_request的执行,开始执行process_response,先导入Response(from scrapy.http import Response)
       eg:return Response(url='http://www.baidu.com',request=request) #只要返回Response对象就不会执行后续的Request,而是直接执行Response
Request对象,停止中间件的执行,将Request重新调度器 #如果返回的是Request对象那就不会执行后续的Request和Reques而是直接到引擎,重新调度
raise IgnoreRequest异常,停止process_request的执行,开始执行process_exception
"""
pass def process_response(self, request, response, spider): #返回数据的中间件带的时response
"""
spider处理完成,返回时调用,默认返回的就是Response
return:
Response 对象:转交给其他中间件process_response
Request 对象:停止中间件,request会被重新调度下载
raise IgnoreRequest 异常:调用Request.errback
"""
return response def process_exception(self, request, exception, spider):
"""
当下载处理器(download handler)或 process_request() (下载中间件)抛出异常的时候调用
:return:
None:继续交给后续中间件处理异常;
Response对象:停止后续process_exception方法,正确执行后续方法
Request对象:停止中间件后续方法,request将会被重新调用下载
"""
return None
注释:1、在项目目录下创建.py文件,将中间件代码写在该文件中,建议文件名称为DownMiddleware
   2、在settings中注册中间件,DOWNLOADER_MIDDLEWARES = {'chouti.middlewares.MyCustomDownloaderMiddleware': 600,},写了几个中间件就注册几个中间件
   3、可以在中间件的process_request中将所有的Request请求添加上请求头,添加cookies等操作,也可以添加代理,判断那个Request需要代理。
#爬虫中间件
class SpiderMiddleware(object):
def process_spider_input(self,response, spider):
"""下载完成,执行,然后交给parse处理,默认返回none"""
pass
def process_spider_output(self,response, result, spider):
"""spider处理完成,返回时调用,return: 必须返回包含 Request 或 Item 对象的可迭代对象(iterable)"""
return result
def process_spider_exception(self,response, exception, spider):
"""异常调用,return: None,继续交给后续中间件处理异常;含 Response 或 Item 的可迭代对象(iterable),交给调度器或pipeline"""
return None
def process_start_requests(self,start_requests, spider):
"""爬虫启动时调用,return: 包含 Request 对象的可迭代对象,由于爬虫只是启动一次所以process_start_requests也只是调用一次 """
return start_requests
注释:1、在项目目录下创建.py文件,将中间件代码写在该文件中,建议文件名称为SpiderMiddleware
   2、在settings中注册中间件,SPIDER_MIDDLEWARES = { 'chouti.middlewares.ChoutiSpiderMiddleware': 600,},写了几个中间件就注册几个中间件

  8、自定义代理

代理,需要在环境变量中设置
from scrapy.contrib.downloadermiddleware.httpproxy import HttpProxyMiddleware 方式一:使用默认
     import os
os.environ
{
      http_proxy:http://root:woshiniba@192.168.11.11:9999/ #有的代理链接是需要用户名和密码的,这个就是root为用户名,woshiniba为密码
https_proxy:http://192.168.11.11:9999/
      } #该方法只需要在爬虫程序文件的类的__init__中添加上就可以了,程序会判断只要是_prxoy结尾的就会吧这个代理拿出来
方式二:使用自定义下载中间件
def to_bytes(text, encoding=None, errors='strict'):
if isinstance(text, bytes):
return text
if not isinstance(text, six.string_types):
raise TypeError('to_bytes must receive a unicode, str or bytes '
'object, got %s' % type(text).__name__)
if encoding is None:
encoding = 'utf-8'
return text.encode(encoding, errors) class ProxyMiddleware(object):#代理中间件
def process_request(self, request, spider):
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': ''},
]
proxy = random.choice(PROXIES)#随机选择一个代理,高明就高明在这个地方,默认代理是不能随机生成的,所有也会有被封的风险。
if proxy['user_pass'] is not None:
request.meta['proxy'] = to_bytes("http://%s" % proxy['ip_port'])#添加上代理
encoded_user_pass = base64.encodestring(to_bytes(proxy['user_pass']))#代理加密,固定加密方法
request.headers['Proxy-Authorization'] = to_bytes('Basic ' + encoded_user_pass) #代理授权
#print "**************ProxyMiddleware have pass************" + proxy['ip_port']
else:
#print "**************ProxyMiddleware no pass************" + proxy['ip_port']
request.meta['proxy'] = to_bytes("http://%s" % proxy['ip_port'])#添加代理 注释:1、在爬虫项目路径中创建代理文件
     2、在settings中注册上代理 DOWNLOADER_MIDDLEWARES = { 'step8_king.middlewares.ProxyMiddleware': 500,}

  9、settings配置文件详解

1. 爬虫名称
BOT_NAME = 'step8_king' 2. 爬虫应用路径
SPIDER_MODULES = ['step8_king.spiders'] #其实就是创建的爬虫程序名称+spiders
NEWSPIDER_MODULE = 'step8_king.spiders'
3. 客户端 user-agent请求头
# USER_AGENT = 'step8_king (+http://www.yourdomain.com)' 4. 禁止爬虫配置(机器人协议)
# ROBOTSTXT_OBEY = True
5. 并发请求数
# CONCURRENT_REQUESTS = 4 #一个线程最大能并发多少个请求,力度粗 6. 延迟下载秒数
# DOWNLOAD_DELAY = 2 默认是秒,每多少秒一次下载 7. 单域名访问并发数,并且延迟下次秒数也应用在每个域名 力度细
# CONCURRENT_REQUESTS_PER_DOMAIN = 2
# 单IP访问并发数,如果有值则忽略:CONCURRENT_REQUESTS_PER_DOMAIN,并且延迟下次秒数也应用在每个IP 力度细
# CONCURRENT_REQUESTS_PER_IP = 3 8. 是否支持cookie,cookiejar进行操作cookie
# COOKIES_ENABLED = True
# COOKIES_DEBUG = True
9. Telnet用于查看当前爬虫的信息,操作爬虫等...
# 使用telnet ip port ,然后通过命令操作
# TELNETCONSOLE_ENABLED = True
# TELNETCONSOLE_HOST = '127.0.0.1'
# TELNETCONSOLE_PORT = [6023,] 10. 默认请求头,死板
# Override the default request headers:
# DEFAULT_REQUEST_HEADERS = {
# 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
# 'Accept-Language': 'en',
# } 11. 定义pipeline处理请求
# ITEM_PIPELINES = {
# 'step8_king.pipelines.JsonPipeline': 700,
# 'step8_king.pipelines.FilePipeline': 500,
# } 12. 自定义扩展,基于信号进行调用
# Enable or disable extensions
# See http://scrapy.readthedocs.org/en/latest/topics/extensions.html
# EXTENSIONS = {
# # 'step8_king.extensions.MyExtension': 500,
# } 13. 爬虫允许的最大深度,可以通过meta查看当前深度;0表示无深度
# DEPTH_LIMIT = 3 14. 爬取时,0表示深度优先Lifo(默认);1表示广度优先FiFo # 后进先出,深度优先
# DEPTH_PRIORITY = 0
# SCHEDULER_DISK_QUEUE = 'scrapy.squeue.PickleLifoDiskQueue'
# SCHEDULER_MEMORY_QUEUE = 'scrapy.squeue.LifoMemoryQueue'
# 先进先出,广度优先
# DEPTH_PRIORITY = 1
# SCHEDULER_DISK_QUEUE = 'scrapy.squeue.PickleFifoDiskQueue'
# SCHEDULER_MEMORY_QUEUE = 'scrapy.squeue.FifoMemoryQueue' 15. 调度器队列
# SCHEDULER = 'scrapy.core.scheduler.Scheduler'
# from scrapy.core.scheduler import Scheduler 16. 访问URL去重
# DUPEFILTER_CLASS = 'step8_king.duplication.RepeatUrl'
"""
17. 自动限速算法
from scrapy.contrib.throttle import AutoThrottle
自动限速设置
1. 获取最小延迟 DOWNLOAD_DELAY
2. 获取最大延迟 AUTOTHROTTLE_MAX_DELAY
3. 设置初始下载延迟 AUTOTHROTTLE_START_DELAY
4. 当请求下载完成后,获取其"连接"时间 latency,即:请求连接到接受到响应头之间的时间
5. 用于计算的... AUTOTHROTTLE_TARGET_CONCURRENCY
target_delay = latency / self.target_concurrency
new_delay = (slot.delay + target_delay) / 2.0 # 表示上一次的延迟时间
new_delay = max(target_delay, new_delay)
new_delay = min(max(self.mindelay, new_delay), self.maxdelay)
slot.delay = new_delay
"""

  10、https证书设置

    Https访问时有两种情况:
1. 要爬取网站使用的可信任证书(默认支持)
DOWNLOADER_HTTPCLIENTFACTORY = "scrapy.core.downloader.webclient.ScrapyHTTPClientFactory"
DOWNLOADER_CLIENTCONTEXTFACTORY = "scrapy.core.downloader.contextfactory.ScrapyClientContextFactory" 2. 要爬取网站使用的自定义证书
DOWNLOADER_HTTPCLIENTFACTORY = "scrapy.core.downloader.webclient.ScrapyHTTPClientFactory"
DOWNLOADER_CLIENTCONTEXTFACTORY = "step8_king.https.MySSLFactory" # https.py
from scrapy.core.downloader.contextfactory import ScrapyClientContextFactory
from twisted.internet.ssl import (optionsForClientTLS, CertificateOptions, PrivateCertificate) class MySSLFactory(ScrapyClientContextFactory):
def getCertificateOptions(self):
from OpenSSL import crypto
v1 = crypto.load_privatekey(crypto.FILETYPE_PEM, open('/Users/wupeiqi/client.key.unsecure', mode='r').read()) #打开本地保存的证书文件
v2 = crypto.load_certificate(crypto.FILETYPE_PEM, open('/Users/wupeiqi/client.pem', mode='r').read())
return CertificateOptions(
privateKey=v1, # pKey对象
certificate=v2, # X509对象
verify=False,
method=getattr(self, 'method', getattr(self, '_ssl_method', None))
)
其他:
相关类
scrapy.core.downloader.handlers.http.HttpDownloadHandler
scrapy.core.downloader.webclient.ScrapyHTTPClientFactory
scrapy.core.downloader.contextfactory.ScrapyClientContextFactory
相关配置
DOWNLOADER_HTTPCLIENTFACTORY
DOWNLOADER_CLIENTCONTEXTFACTORY

Scrapy框架2的更多相关文章

  1. Python爬虫Scrapy框架入门(2)

    本文是跟着大神博客,尝试从网站上爬一堆东西,一堆你懂得的东西 附上原创链接: http://www.cnblogs.com/qiyeboy/p/5428240.html 基本思路是,查看网页元素,填写 ...

  2. Python爬虫Scrapy框架入门(1)

    也许是很少接触python的原因,我觉得是Scrapy框架和以往Java框架很不一样:它真的是个框架. 从表层来看,与Java框架引入jar包.配置xml或.property文件不同,Scrapy的模 ...

  3. Scrapy框架使用—quotesbot 项目(学习记录一)

    一.Scrapy框架的安装及相关理论知识的学习可以参考:http://www.yiibai.com/scrapy/scrapy_environment.html 二.重点记录我学习使用scrapy框架 ...

  4. Python爬虫从入门到放弃(十一)之 Scrapy框架整体的一个了解

    这里是通过爬取伯乐在线的全部文章为例子,让自己先对scrapy进行一个整理的理解 该例子中的详细代码会放到我的github地址:https://github.com/pythonsite/spider ...

  5. Python爬虫从入门到放弃(十二)之 Scrapy框架的架构和原理

    这一篇文章主要是为了对scrapy框架的工作流程以及各个组件功能的介绍 Scrapy目前已经可以很好的在python3上运行Scrapy使用了Twisted作为框架,Twisted有些特殊的地方是它是 ...

  6. python爬虫scrapy框架——人工识别登录知乎倒立文字验证码和数字英文验证码(2)

    操作环境:python3 在上一文中python爬虫scrapy框架--人工识别知乎登录知乎倒立文字验证码和数字英文验证码(1)我们已经介绍了用Requests库来登录知乎,本文如果看不懂可以先看之前 ...

  7. 一个scrapy框架的爬虫(爬取京东图书)

    我们的这个爬虫设计来爬取京东图书(jd.com). scrapy框架相信大家比较了解了.里面有很多复杂的机制,超出本文的范围. 1.爬虫spider tips: 1.xpath的语法比较坑,但是你可以 ...

  8. 安装scrapy框架的常见问题及其解决方法

    下面小编讲一下自己在windows10安装及配置Scrapy中遇到的一些坑及其解决的方法,现在总结如下,希望对大家有所帮助. 常见问题一:pip版本需要升级 如果你的pip版本比较老,可能在安装的过程 ...

  9. 关于使用scrapy框架编写爬虫以及Ajax动态加载问题、反爬问题解决方案

    Python爬虫总结 总的来说,Python爬虫所做的事情分为两个部分,1:将网页的内容全部抓取下来,2:对抓取到的内容和进行解析,得到我们需要的信息. 目前公认比较好用的爬虫框架为Scrapy,而且 ...

  10. 利用scrapy框架进行爬虫

    今天一个网友问爬虫知识,自己把许多小细节都忘了,很惭愧,所以这里写一下大概的步骤,主要是自己巩固一下知识,顺便复习一下.(scrapy框架有一个好处,就是可以爬取https的内容) [爬取的是杨子晚报 ...

随机推荐

  1. 在Linux命令行下发送html格式的邮件

    在Linux利用formail+sendmail来发送带图片的邮件 formail接收html格式的文件作为邮件的内容,这样就可以解决发送带图片邮件的问题了,因为html中可以插入图片,只要给出的im ...

  2. 5 月 35 日临近,Google 无法访问,可以使用 Google IP 来解决。

    每年都会有几天那啥,你懂的. 直接使用 Google 的域名访问经常会打不开,而使用 Google 的 IP 就会很顺畅. 使用 Chrome 浏览器我们经常都会在地址栏直接搜索,所以我们只要添加一个 ...

  3. JPA(Java Persistence API)Java持久化API-介绍

    JPA全称: Java Persistence API JPA的宗旨是为POJO提供持久化标准规范,能够脱离容器独立运行,很方便开发和测试.JPA通过JDK 5.0注解或XML描述对象-关系表的映射关 ...

  4. diamond源码阅读-diamond-server

    diamond-server 1 增加一条数据 /diamond-server/admin.do?method=postConfig 1.1 调用 this.configService.addConf ...

  5. 回调函数(callback)是什么?

    你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货.在这个例子里,你的电话号码就叫回调函数,你把电话留给 ...

  6. Android Studio Error -- Could not create the Java Virtual Machine

    :app:dexDebug Error: Could not create the Java Virtual Machine. Error: A fatal exception has occurre ...

  7. 小知识,大智慧(restframework 拾忆)

    一.直接对query_set序列化,在页面展示的效果是Unicode 编码格式 ,可在json 序列化时候加入一个参数 course_query = DegreeCourse.objects.all( ...

  8. PHP中foreach详细解读

    oreach 语法结构提供了遍历数组的简单方式.foreach 仅能够应用于数组和对象,如果尝试应用于其他数据类型的变量,或者未初始化的变量将发出错误信息.有两种语法: foreach (array_ ...

  9. LeetCode Problem 169: Majority Element查找多数元素

    描述:Given an array of size n, find the majority element. The majority element is the element that app ...

  10. VLC 媒体播放器

    VLC 媒体播放器 VLC 媒体播放器是一个便携式. 免费.开源. 跨平台的媒体播放器. VideoLAN 项目的流式媒体服务器.分为Windows Phone版本和Android版本. 下载地址: ...