加代理
| |
| def get_proxy(self): |
| import requests |
| res=requests.get('http://192.168.1.143:5010/get/').json() |
| if res.get('https'): |
| return 'https://'+res.get('proxy') |
| else: |
| return 'http://' + res.get('proxy') |
| def process_request(self, request, spider): |
| |
| |
| |
| pro=self.get_proxy() |
| request.meta['proxy'] = pro |
| |
| print(request.meta) |
| return None |
| |
| |
| |
| |
| -记录日志 |
| -把当前爬取的request对象,return出去,会被引擎重新放回调度器,等待下次执行 |
加cookie,修改请求头,随机生成UserAgent
| |
| print(request.cookies) |
| request.cookies['name']='pyy' |
| request.cookies=从cookie池中取出来的cookie |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| -fake_useragent模块,可以随机生成user-aget |
| from fake_useragent import UserAgent |
| ua = UserAgent() |
| print(ua.ie) |
| print(ua.firefox) |
| print(ua.chrome) |
| print(ua.random) |
| |
| |
| from fake_useragent import UserAgent |
| ua = UserAgent() |
| request.headers['User-Agent'] = ua.random |
| print(request.headers) |
集成selenium
| |
| |
| |
| |
| |
| 字符串转bytes |
| -方式一:lqz'.encode(encoding='utf-8') |
| -方式二:bytest('字符串',encoding='utf-8') |
| bytes转字符串 |
| -方式一:b'lqz'.decode(encoding='utf-8') |
| -方式二:str('bytes格式',encoding='utf-8') |
| |
| |
| |
| |
| # 使用步骤:只用selenium爬取cnblogs的首页和下一页 (一旦使用selenium速度就慢) |
| -第一步:在爬虫类的类属性中写 |
| class CnblogsSpider(scrapy.Spider): |
| bro = webdriver.Chrome(executable_path='./chromedriver.exe') |
| -第二步:在中间件中使用selenium爬取 |
| if request.meta.get('user_selenium'): #有的用,有的不用 |
| spider.bro.get(request.url) |
| from scrapy.http import HtmlResponse |
| response = HtmlResponse(url=request.url, body=bytes(spider.bro.page_source, encoding='utf-8')) |
| return response |
| else: |
| return None |
| |
| -第三步:在爬虫类中关闭 |
| def close(self, spider, reason): |
| self.bro.close() |
| |
| |
| |
| -我们想的话:把爬取过的网址,放在集合中,下次爬取之前,先看集合中有没有,如果有,就不爬了 |
| -源码在哪去的重?调度器---》调度器源码 |
| |
| |
| |
| def enqueue_request(self, request: Request) -> bool: |
| |
| if not request.dont_filter and self.df.request_seen(request): |
| |
| |
| |
| return False |
| return True |
| |
| -self.df 是去重类的对象 RFPDupeFilter |
| -在配置文件中如果配置了:DUPEFILTER_CLASS = 'scrapy.dupefilters.RFPDupeFilter'表示,使用它作为去重类,按照它的规则做去重 |
| -RFPDupeFilter的request_seen |
| def request_seen(self, request: Request) -> bool: |
| |
| fp = self.request_fingerprint(request) |
| |
| if fp in self.fingerprints: |
| return True |
| |
| self.fingerprints.add(fp) |
| return False |
| |
| |
| -生成指纹,指纹是什么? |
| -www.cnblogs.com?name=lqz&age=19 |
| -www.cnblogs.com?age=19&name=lqz |
| -上面的两种地址生成的指纹是一样的 |
| |
| from scrapy.utils.request import RequestFingerprinter |
| from scrapy import Request |
| |
| fingerprinter = RequestFingerprinter() |
| request1 = Request(url='http://www.cnblogs.com?name=lqz&age=20') |
| request2 = Request(url='http://www.cnblogs.com?age=19&name=lqz') |
| |
| res1 = fingerprinter.fingerprint(request1).hex() |
| res2 = fingerprinter.fingerprint(request2).hex() |
| print(res1) |
| print(res2) |
| |
| |
| |
| |
| -根据配置的去重类RFPDupeFilter的request_seen方法,如果返回True,就不爬了,如果返回False就爬 |
| -后期咱们可以使用自己定义的去重类,实现去重 |
| |
| |
| |
| -如果是集合:存的数据库越多,占内存空间越大,如果数据量特别大,可以使用布隆过滤器实现去重 |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| from pybloom_live import BloomFilter |
| |
| bf = BloomFilter(capacity=10) |
| url = 'www.baidu.com' |
| bf.add(url) |
| bf.add('aaaa') |
| bf.add('ggg') |
| bf.add('deww') |
| bf.add('aerqaaa') |
| bf.add('ae2rqaaa') |
| bf.add('aerweqaaa') |
| bf.add('aerwewqaaa') |
| bf.add('aerereweqaaa') |
| bf.add('we') |
| |
| |
| print(url in bf) |
| print("wa" in bf) |
| |
| |
| |
| |
| -原来使用一台机器爬取cnblogs整站 |
| -现在想使用3台机器爬取cnblogs整站 |
| |
| -1 去重集合,我们要使用同一个----》redis集合 |
| -2 多台机器使用同一个调度器:Scheduler,排队爬取,使用同一个队列 |
| |
| |
| |
| |
| 第一步:安装scrapy-redis ---》pip3 install scrapy-redis |
| 第二步:改造爬虫类 |
| from scrapy_redis.spiders import RedisSpider |
| class CnblogSpider(RedisSpider): |
| name = 'cnblog_redis' |
| allowed_domains = ['cnblogs.com'] |
| |
| redis_key = 'myspider:start_urls' |
| |
| 第三步:配置文件配置 |
| |
| |
| REDIS_HOST = 'localhost' |
| REDIS_PORT = 6379 |
| DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" |
| SCHEDULER = "scrapy_redis.scheduler.Scheduler" |
| |
| ITEM_PIPELINES = { |
| 'cnblogs.pipelines.CnblogsFilePipeline': 300, |
| 'cnblogs.pipelines.CnblogsMysqlPipeline': 100, |
| 'scrapy_redis.pipelines.RedisPipeline': 400, |
| } |
| 第四步:在多台机器上启动scrapy项目,在一台机器起了多个scrapy爬虫进程,就相当于多台机器 |
| -进程,线程,协程。。。 |
| -进程间数据隔离 IPC |
| |
| 第五步:把起始爬取的地址放到redis的列表中 |
| lpush mycrawler:start_urls http://www.cnblogs.com/ |
| |
| |
| -django:大而全,web开发用的东西,它都有 |
| -Flask:小而精,只能完成请求与响应,session,cache,orm,admin。。。统统没有 |
| -很多第三方框架,flask完全可以变成django |
| -----同步框架----- django从3.x 改成了异步框架 |
| |
| ----以下是异步框架-------- |
| -Tornado:非常少了,ptyhon2.x上,公司里用的多一些 |
| -Sanic : python 3.6 及以上 |
| -FastAPI |
| |
| Flask是一个基于Python开发并且依赖jinja2模板(模板语言)和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后触发Flask框架,开发人员基于Flask框架提供的功能对请求进行相应的处理,并返回给用户,如果要返回给用户复杂的内容时,需要借助jinja2模板来实现对模板的处理,即:将模板和数据进行渲染,将渲染后的字符串返回给用户浏览器。 |
| |
| “微”(micro) 并不表示你需要把整个 Web 应用塞进单个 Python 文件(虽然确实可以 ),也不意味着 Flask 在功能上有所欠缺。微框架中的“微”意味着 Flask 旨在保持核心简单而易于扩展。Flask 不会替你做出太多决策——比如使用何种数据库。而那些 Flask 所选择的——比如使用何种模板引擎——则很容易替换。除此之外的一切都由可由你掌握。如此,Flask 可以与您珠联璧合。 |
| |
| 默认情况下,Flask 不包含数据库抽象层、表单验证,或是其它任何已有多种库可以胜任的功能。然而,Flask 支持用扩展来给应用添加这些功能,如同是 Flask 本身实现的一样。众多的扩展提供了数据库集成、表单验证、上传处理、各种各样的开放认证技术等功能。Flask 也许是“微小”的,但它已准备好在需求繁杂的生产环境中投入使用 |
| |
| |
| |
| from flask import Flask |
| |
| app = Flask(__name__) |
| |
| |
| @app.route('/index') |
| def index(): |
| return '你看到我了' |
| |
| |
| if __name__ == '__main__': |
| app.run(host='127.0.0.1',port=8080) |
| |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)