python爬虫入门

news2024/11/19 21:21:32

基础知识

HTTP协议

我们浏览网页的浏览器和手机应用客户端与服务器通信几乎都是基于HTTP协议,而爬虫可以看作是一个另类的客户端,它把自己伪装成浏览器或者手机应用客户端,按照自己的逻辑贪婪的向服务器索取数据,如何向服务器索取数据,所以了解HTTP协议就显得很有必要了。

HTTP协议中文名称是超文本传输协议,是一个基于请求与响应模式的、无状态的、应用层的协议,常基于TCP的连接方式。请求和响应模式很好理解,客户端发送请求,服务器响应客户端的请求,就像学校食堂打菜一样,你和打菜阿姨说要哪份菜,她才会给你盛哪份菜。

无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。形象点说,可以把服务器看成是没有记忆的大学食堂打饭打菜,在每次请求中,阿姨并不知道你之前有没有打过菜,也不知道你是不是合法的学生,所以你只能一边举着学生证一边和阿姨说我要这个菜,阿姨看到你的学生证后才会给你打菜,而这个学生证就是你每次需要重传的数据信息。

当我们在浏览器地址栏中输入http://www.bilibili.com 并敲入回车后,浏览器会构造HTTP请求发送到服务器,在收到服务器的HTTP响应后,浏览器会解析页面,继续向服务器请求图片、视频、js脚本等数据,直到页面加载完成,最终展示给我们的就是B站主页了。这是我用Fiddler抓的包,展示的是HTTP最原生的面貌,接下来我就根据这张图具体的讲解HTTP协议,以及写爬虫需要关注的一些点。

HTTP请求由三部分组成,分别是: 请求行、消息报头、请求正文。 在接收和解释请求消息后,服务器返回一个HTTP响应消息,HTTP响应也是由三个部分组成,分别是:状态行、消息报头、响应正文。

HTTP方法

HTTP请求的请求行以一个方法符号开头,以空格分开,后面跟着请求的URI和协议的版本。请求方法都是大写,有很多种,常见的有GET POST DELETE PUT,各种方法之间的区别不大。

这里罗列了一些常用的方法,一般来讲,GET表示向服务器请求URI对应的资源,POST表示向服务器提交数据,DELETE表示删除数据,PUT表示修改数据。但这都是一种约定,没有强制的要求,如果你碰见用DELETE方法提交数据也没必要大惊小怪。在实际写爬虫的过程中,我们只需要按照抓包请求构造数据即可,没有必要在意用了什么方法。

报头字段

重点讲解几个写爬虫需要关注的字段

  • User-Agent 出现在请求报头中,表示客户端的操作系统、浏览器型号版本等信息。服务器可以根据此报头向客户端返回不同的页面以适应客户端。有些网站(知乎)会校验此报头,不填写或者不主流的报头都不能拿到正常的页面。因此自己在写爬虫的时候最好将从浏览器中拷贝到代码中。
  • Cookie 出现在请求抱头中,前面我们说过HTTP是基于请求与响应模式并且无状态的协议,之前举了打菜阿姨的例子,Cookie就相当于每次请求中的学生证,它可以记录用户的身份信息。当我们自己写爬虫的时候,如果需要登陆,并且登陆又有验证码或者短信验证时,最简单的方法就是从浏览器中把cookie拷贝到爬虫中,就可以骗过服务器了。
  • Set-Cookie 出现在响应抱头中,让客户端更新页面关联的Cookie,还是拿食堂阿姨的例子,如果你的响应报头有这个字段,意思就是阿姨重新给你了一个学生证,下次打饭你得用最新的学生证,原来的学生证不好使。如果你在模拟浏览器或者客户端登陆,需要将此报头更新已有的Cookie,不过Scrapy和requests都可以自动更新,因此不需要你再手动设置。
  • Content-Type 标明请求正文或者响应正文的格式,客户端或者服务器会根据此字段选择合适的方式解析正文内容,以下是一些常见的值

  • Content-Length 标明请求正文或者响应正文的长度,在使用requests构造请求的时候,我们不需要显式的加上此字段,requests会根据请求正文自动计算添加。
  • Content-Encoding 在某些情况下,正文会讲过压缩后传输,此字段会指明压缩的类型(gzip和压缩参数)
  • Transfer-Encoding 如果正文内容过长,HTTP协议允许将此字段设置为chunked,然后分块传输响应正文
  • Connection 在HTTP1.1之前的版本,不支持持久连接,所谓的持久链接意思就是:HTTP协议一般通过TCP协议实现,客户端和服务器经过TCP三次握手建立连接,在请求和响应结束之后,此连接继续保持,当之后还有请求的时候,就不需要重新通过三次握手再建立连接,这样可以极大的降低客户端和服务器的IO负载。

在自己写爬虫的时候,我们可以根据浏览器的抓包数据有选择的添加一些请求报头,其实大部分情况下都可以直接使用浏览器中的请求头,为了避免不必要的麻烦,尽可能像的模仿浏览器总是没有错的。

响应码

响应消息的第一行的状态行包括HTTP的协议版本、状态码、状态码含义。按照约定

  • 2xx表示请求成功
  • 3xx表示重定向
  • 4xx表示客户端错误(403 Forbiden 404 Not Found)
  • 5xx表示服务器错误(502 网关错误)

爬虫开发

一般来说开发爬虫的过程是这样的

  1. 抓包分析获取数据的URL
  2. 通过python从上一步的URL获取数据
  3. 从上一步获取的HTML页面或者JSON数据中解析出感兴趣的数据
  4. 存储数据

下面就讲解这四个关键点

抓包发包工具

写爬虫的第一步就是分析想要的数据浏览器是通过什么URL拿到的,抓包也就在所难免。最好用的抓包工具当然是谷歌浏览器了,右键检查,选中网络,重新刷新页面就可以看到加载此网页所有的HTTP请求了,如果此链接有跳转地址,跳转之前的HTTP请求会被清掉,所以记得选上preserve log,尤其是登陆的时候,一般都会有跳转。

 再介绍另外两个HTTP抓包工具——Fiddler和Charles,分别在windows和macos使用。它们可以为我们展示更多HTTP的细节,将请求和响应都调至Raw模式下,我们就可以一睹HTTP请求和响应的真实面貌。

通过抓包分析出具体的URL后,想进一步确认自己构造的参数和报头能否正确获取到数据,应该怎么做呢?不怕,postman可以帮你,你可以很轻松的选择方法,定义header,添加各种类型的body。

 

python请求数据

讲完了基本的HTTP协议知识后,大家可能会疑问那我该如何模仿浏览器或者手机客户端去向服务器发送HTTP请求呢?python的原生库urllib、第三方库requests、pycurl等都支持HTTP协议,既然有这么多工具可以用,大家可能就又有疑问该选择哪个工具了。在此我特地安利大家用一下requests,它让爬虫变得如此简单,让你再也不用为字符编码、重定向、cookie、响应解压缩烦恼了。如果你坚持用原生的库,那么有以下问题需要你一一解决,这些都是当年自己趟过的坑,绝非危言耸听。

  1. 需要自己判断服务器返回数据的编码格式,如果这个地方你不能正确判断,那恭喜你之后的每一步,你都必须面对乱码的问题
  2. 重定向,urllib不能自动判断重定向,需要自己解析重定向的链接并重新请求
  3. 如果模拟登陆,你必须要手动保证Cookie正确更新和发送
  4. 很多情况下响应正文是压缩过的,需要做解压处理
  5. 对于比较长的响应正文,服务器会将正文分段传输,所以还需要你做拼接操作
  6. 原生的urllib对HTTPS和持久连接都支持不好

当你花了一整天,写了好几百行的代码终于解决上面的问题后,而你旁边的同事可能早已经把数据下载完并愉快的约妹子去了。所以用requests吧,兄弟们用了都说好。下面我用两个例子讲解一下如何用requests获取想要的数据,并教你如何解决这些问题:

  • 如何发送不同方法的请求
  • 如何保存cookie
  • 如何添加代理
  • 如何处理编码问题

B站

假如我想下载B站里面某位小姐姐所有上传的视频,应该怎么办呢?首先你需要找到这位小姐姐的视频主页

 

但是通过谷歌浏览器右键查看页面源码,没有从html中找到这些视频的播放信息,唯一的可能就是视频数据是通过js脚本调用服务器获取,然后生成的这张页面。爬虫小白可能会疑问,难道我需要像浏览器一样分析js脚本,然后模拟js执行吗?其实不用这么复杂,只需要简单的分析抓包结构,就可以找到请求URL了。

获取视频的URL: http://space.bilibili.com/ajax/member/getSubmitVideos?mid=79415852&pagesize=30&tid=0&page=1&keyword=&order=senddate

那么问题又来了,这个URL的其他参数是干啥的呢?凭经验,mid肯定是这位小姐姐的用户id,page和pagesize是负责分页用的,keyword和是用来搜索的关键字,order是排序选项,剩下的tid是干啥的呢?其实写爬虫很多时候都会遇到这种问题,不知道某个参数的含义,也不确定正确的取值范围,需要一些尝试和运气,这里我们不管它就好。而返回的字段中有一个aid,那肯定是视频的id,有这个就可以自己拼接出播放链接了。

是不是很简单,通过response.ok查看请求是否正确返回,因为此接口的数据为json格式,直接通过response.json()就可以直接拿到格式化的数据。

知乎

虽然现在知乎对未登录用户展示的内容越来越多,但是仍会有一些限制,用爬虫模拟登陆可以之后再去爬取数据,可以避免很多不必要的麻烦,现在就讲一讲如何用requests模拟用户登陆。

还是和之前一样,在登陆页面打开谷歌浏览器的抓包窗口,输入用户名和密码点击确定,然后在茫茫请求中找到发送登陆信息的那个HTTP请求即可,功夫不负有心人,我们终于找到了登陆的请求。

等等,请求里面还有一个_xsrf,这是一个什么鬼参数,其实呢这是一个防止跨站请求伪造而生成的一个随机数,可以通过解析https://www.zhihu.com/#signin 页面获取,这一部分我在下面会讲解如何HTML获取数据,现在假设我们已经拿到这个数据了,如何将用户名和密码登陆呢?

 

如果我们想要自动保存Cookie信息,只需要生成一个Session对象,之后所有的请求通过此对象完成,requests会像浏览器一样自动更新cookie信息,并在每次请求的时候加上cookie,因此在成功的发送post登陆请求之后,就可以用session在保持登陆状态请求数据了。需要注意的是在请求的时候我特意去掉了Cookie和Content-Length报头,因为requests会自动加上,所以不需要我们特意关注。

python解析数据

因为个人在解析数据的时候遇到过很多编码的坑,所以在继续讲解之前告诉大家一些如何避免编码问题的方法。python2中有两种字符串:unicode和str,它们分别对应python3中的str和bytes。如何定义这两种类型的变量在下图中给大家列出来了。

以python3为例讲解这两种类型的区别。python3中的str每一个字符可以存储一个英文字母、一个汉字甚至一个emoji表情,它可以通过特定的编码方式,例如utf-8或者gbk生成bytes,在不同的编码格式下,可能需要2-3个字符常能表示一个汉字。bytes可以指定解码格式解码生成str,如果指定的解码格式不匹配,就会导致乱码问题。为了避免乱码问题,最好的方式就是使用str,等到需要写入文件或者数据库的时候,再指定写入的编码格式,用好这个准则,我们可以避免百分之九十的编码问题。

HTTP响应的数据格式有很多,例如文本、json、html,对应的解析方式也很多。通用一点,用python内置库正则匹配找到想要的数据,但是这种方法相对来说比较麻烦,而且不好维护,比较适合文本类型的数据,但HTTP响应正文基本都是json和HTML,这种方式适用面比较窄。

当请求的数据是json格式时,我们可以很方便的用requests反序列化返回内容,取出感兴趣的数据。但是当HTTP返回的数据是html的时候,我们该如何操作,就像刚才知乎登陆的例子中,如何快速从html中解析想要的数据呢?

专门用来解析html的第三方库有很多,例如beautifulsoup、pyquery。个人推荐使用pyquery,因为它可以使用jquery的方式选取元素,而且支持xpath,以后上手scrapy会很容易。只要先请求到这个页面,然后解析出_xsrf,配合之前的登陆请求,我们就可以完整的实现用python模拟浏览器登陆知乎了。

 

使用起来是不是相当的简单,我们只要通过谷歌浏览器找到对应DOM元素,根据属性名就可以非常快速的找到想要的数据。需要注意的是response.content和response.text,这都是返回的body正文,但是前者是bytes,后者是str,requests已经帮助我们把响应正文按照正确的编码格式进行了解码,根据我们之前的阐述的原则,尽量使用str,所以26这个地方我用的是response.text。

存储数据

根据数据量的不同以及数据类型的不同,数据的存储选择也很多。如果爬取的是图片、音频、视频等多媒体文件,直接按照文件形式存储就好了。如果是一些文本,数字等数据,一般有这么几种选择:

  • 输出到屏幕
  • 写入文件(txt csv)
  • 写入数据库 (mysql sqlite mongo)

如果数据量非常小,可以选择直接输出到屏幕(这种情况貌似也不需要爬虫),因为终端存储的数据量很少,而且因为没有持久化,关闭窗口就意味着数据丢失,不建议使用。

在数据量小且不愿意折腾数据库的情况下,可以把爬取的数据写入文件,但是这种情况不能随取随用,也不方便做数据分析,需要手动处理。

当数据量较多,而且需要快捷的分析数据,推荐使用数据库存储数据,大型的数据库mysql, mongo功能齐全,可以分方便的进行数据分析,而且也很容易实现分布式扩展,当你需要多进程甚至多机器运行爬虫的时候,这些数据库可能是最好的选择。sqlite相对来说功能要少很多,python原生支持,依赖少,数据量不算太大的情况下可以考虑使用。

爬虫示例

下面给出一个简单的例子,为大家展示如何使用上述python库实现一个完整的爬虫。一些热门的知乎话题最多有1000条精华回答,这个例子就是爬取这些精品答案。图示页面就是回答列表,每页有二十个答案,最多有五十页。但是此页面没有完整的回答信息,需要通过显示全部对应的链接进入回答详情页才能获取完整的答案,所以我们的爬虫策略就是通过回答列表找到所有精华回答链接,再通过回答链接获取内容。而且这些页面不需要登陆也能访问,因此可以省去模拟登陆。

开发环境

python是跨平台语言,但不同平台不同版本的python略微有一些差异,考虑到大家使用windows平台的较多,我在windows和ubuntu的python3.5验证过此代码,其他平台和其他python版本下可能需要做一些修改。集成开发环境推荐使用Pycharm,这是一个跨平台良心IDE,各大操作系统下都有免费的社区版本可以下载。

安装依赖库:

pip install requests pyquery SQLAlchemy

运行代码:

python scrawl.py

代码解释

因为数据量不大,采用sqlite存储,可以很方便的用命令行或者桌面客户端查看数据。

反爬虫策略和应对方式

稍微大一些的网站都会有一些反爬虫策略,简单一点的根据User-Agent过滤,例如知乎,我们只需要设置为和浏览器相同即可。复杂一点的会限制非登陆用户,也只需要按照之前例子中的方式登陆,或者干脆先用浏览器登陆好,然后在第一次访问的时候带上浏览器中的cookie就好,实现起来难度不大。但是有不少网站,例如豆瓣和github,在检测到某一客户端频繁访问后,会直接封锁ip,这个问题解决起来就相当的棘手和蛋疼了。

解决方法也挺简单,我们只需要找到足够多的代理ip就可以了,只要策略得当,短时间内不要过度频繁的使用同一ip代码,或者当某一ip地址被封锁后马上切换到其他的ip代理,这样就可以保证高效的爬取数据了。那如何找到代理ip并且如何使用了,其实免费的代理ip很多,我们用百度搜索代理ip就可以找到很多网站

找到代理ip后,就可以用上面的方式很轻松的使用代理ip了,但是网上免费的代理ip质量不好,很多不可用,而且速度慢、不稳定,请求的时候最好设置一下超时时间。我之前在爬github的时候,会专门写一个爬虫从这些网站搜集代理ip地址,一旦检测到被github封锁,就随机选取一个代理ip使用,如果发现代理ip不可用,不断的更换知道可用的代理ip为止,每个代理ip使用的次数也会有一定的限制,保证爬虫在整个执行期间不会因为ip封锁而不可用。

异常及性能

曾经我遇到过这样的状态,写好并运行爬虫一个小时之后,因为网络抖动或者某一种特殊的页面导致解析失败,整个爬虫运行终止,这就蛋疼了。如果日志打印不充分,我连运行失败的原因都清楚,更别说修复问题,即使修复好重新运行,又要花一个小时才能到刚才的进度,费时费力。

爬虫出现异常的情况实在是太多:网络抖动、解析页面失败、反爬虫被屏蔽、写入数据异常、代码逻辑错误等等都会导致进程终止,而一般爬虫需要数小时甚至数天数周的运行,每一次的运行失败都是时间巨大的浪费。因此一定需要在可能出现异常的地方接住异常,保证爬虫不会终止,并记录日志,这些错误日志不仅可以快速的帮助我们定位错误,在出错不多的情况下,我们甚至不需要修改代码重新运行,只需要人肉补全这些数据就好。

如果发现自己的爬虫运行效率太低,爬取速度太慢,并发对于提升爬虫速度是一个不错解决方案,因为GIL的存在,多进程并发模式对于python提速更优,我们可以使用生产者消费者的模式将爬虫任务进行拆分,从而实现多进程或者分布式。一般来说可以将HTTP请求的数据、解析数据、存储数据分别用不同的进程实现,这些进程之间通过消息队列进行通信,保证每个进程无状态,就可以非常容易的实现多进程扩展。即使某一类进程出现异常,也不需要重新启动所有的进程,只需要修复好代码重新启动,就可以实现断点续爬了。

一些常用的分布式工具:redis、rabbitmq、scrapy、celery、you-get

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/147688.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【实操篇】Linux的网络环境及其配置

目录 ●Linux网络环境原理图(NAT模式) ●虚拟网络编辑器对虚拟网卡ip进行修改(VMnet-) ●查看网关( VMnet8->WLAN) ●Linux网络ip配置 1.修改配置文件去获取固定ip 2.自动获取ip连接网络 ●Linux网络环境原理图&#xff…

【vue2】计算属性(computed)与侦听器(watch)详解

🥳博 主:初映CY的前说(前端领域) 🌞个人信条:想要变成得到,中间还有做到! 🤘本文核心:计算属性与侦听属性的用法 目录(文末有给大家准备好的Xmind思维导图&#xf…

JAVA单商户商城系统源码,前(vue)后(SpringBoot)端分离,支持多平台(h5,小程序,app)

前言 完整代码下载地址:JAVA单商户商城系统源码 linjiashop 是一个基于Spring Boot和Vue.js的web商城系统 linjiashop 包含了商城的后台管理系统,手机h5,小程序版本 linjiashop 采用web-flash作为底层基础框架搭建,开发过程遇到问题请多阅…

Js中闭包的概念和具体使用

前言闭包在js里面是一个比较抽象的概念,但在面试里,是一个必问的话题,往往面试官希望你列举一些使用闭包的例子或手写一个闭包闭包,简单一句话讲就是能够读取其他函数内部变量的函数,当需要函数内容部的变量被外部的代码所访问时那闭包就非常有用了的,如今,很多框架里面的高级特…

Spring整合Mybatis和Junit

文章目录1 Spring整合Mybatis环境搭建整合步骤使用的注解详解2 Spring整合Junit整合Junit步骤使用的注解详解1 Spring整合Mybatis 大体需要做两件事, 第一件事是:Spring要管理MyBatis中的SqlSessionFactory 第二件事是:Spring要管理Mapper接口的扫描 具体该如何实现…

6.Isaac教程--在 C++ 中开发 Codelet

在 C 中开发 Codelet 本教程的目标是用 C 开发两个小码:第一个实际上是一台“ping”的机器,而第二个侦听并摄取“ping”消息。 对于本教程,不需要外部依赖项或特殊硬件。 文章目录在 C 中开发 Codelet创建新应用程序为应用程序创建一个新目录…

【Linux】Linux的基本指令(一)

文章目录1、ls 指令2、pwd 命令3、cd 指令4、touch 指令5、mkdir 指令6、rmdir和rm 指令7、man 指令8、cp 指令9、mv 指令10、cat11、echo(输出,输入,追加重定向)12、wc13、more14、less1、ls 指令 语法: ls[选项][目录或文件] 功能&#xff…

2. 矩阵(matrix)、数组、列表(list)、数据框(data.frame.....)

课程视频链接:https://www.bilibili.com/video/BV19x411X7C6?p1 本笔记参照该视频,笔记顺序做了些调整【个人感觉逻辑顺畅】,并删掉一些不重要的内容 系列笔记目录【持续更新】:https://blog.csdn.net/weixin_42214698/category_…

电脑总是开机黑屏,开机两次才能成功的解决办法:更新BIOS(七彩虹H410M-T PRO)

参考:七彩虹主板更新BIOS的方法 前段时间电脑出问题了,每当我第一次开机都会黑屏,要强制关机第二次开能开机,导致每次都开机很久很久,心情也不好 有时候开机等他一会,大概两分钟,会报如下错误&a…

C++课程成绩管理与分析系统[2023-01-07]

C课程成绩管理与分析系统[2023-01-07] C实习指导书 编写:潘林 修订:邓吉秋 一、实习目的 学生通过此次实习, 应达到如下要求: 熟练使用一种 C开发环境,包括 IDE 与编译器;掌握 C程序的编写 过程与调试&…

Sentinel 是什么

Sentinel是什么 Sentinel 官网:introduction | Sentinel 随着微服务的流行,服务与服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。 Sentinel 具有以下特征 丰富…

Rancher部署分布式任务调度系统XXL-JOB通过拉取Docker公共镜像方式

通过Rancher部署分布式任务调度系统XXL-JOB我了解到有两种方式,一种是拉取xxl-job的源代码打包通过Jenkins部署,另一种简单的是直接拉取官方镜像,本文主要讲后面这种。 1、打开Docker公共镜像仓库,搜索xxl-job,复制镜…

GNN笔记系列 3

GNN笔记系列 21.Graph1.1Directed Graphs1.2Symmetric Graphs1.3Unweighted Graphs2.Graph Shift Operators(GSO)2.1Degree Matrix2.2Laplacian Matrix2.3Graph Shift Operator SSS3.Graph Signals4.Graph Convolutional Filters5.Time convolutions and graph convolutions6.G…

itertools包介绍——可以不用 但不能不知道——python包推荐系列

背景1 今天在看一个开源包,发现他的requirements.txt里面放着more_itertools包。 这个包的名字还是挺有意思的,在itertools包前面加上了一个more。难道是python自带的包itertools的加强版? 后来查了一下,这个包,果然…

高并发系统设计的15个锦囊

记得很久之前,去面试过字节跳动。被三面的面试官问了一道场景设计题目:如何设计一个高并发系统。当时我回答得比较粗糙,最近回想起来,所以整理了设计高并发系统的15个锦囊,相信大家看完会有帮助的。 如何理解高并发系统…

【云原生 | 51】Docker三剑客之Docker Compose第二节

🍁博主简介: 🏅云计算领域优质创作者 🏅2022年CSDN新星计划python赛道第一名 🏅2022年CSDN原力计划优质作者 🏅阿里云ACE认证高级工程师 🏅阿里云开发者社区专…

打卡第11天|力扣20. 有效的括号 、 1047. 删除字符串中的所有相邻重复项 、150. 逆波兰表达式求值 。

今天是打卡第十一天,题目主要是栈结构的运用20. 有效的括号题目链接如下:20. 有效的括号我们挨个遍历字符串,每有一个向左的字符串我们就往栈里面存一个向右的括号,遍历到向右的括号时,如果栈中类型相同就弹出&#xf…

在日本之后,中国也发布新型光刻机,ASML加快对中国出口光刻机

由于美国的影响,ASML对中国出售光刻机一直都在摇摆之中,不过2022年底至少有三家中国芯片企业获得ASML的光刻机,显示出ASML的态度再次发生变化,导致如此结果或许在于中国近期宣布的新型光刻机。一、开辟芯片制造新技术说到绕开ASML…

2022年9月CSP认证题解 如此编码(k进制),何以包邮?(背包问题),吉祥物投票(珂朵莉树、懒标记、并查集)

T1 如此编码 思路 由公式 和前缀乘积定义 得mb1a1b2⋅⋅⋅a1a2⋅⋅⋅an−1bnmb_1a_1\times b_2a_1\times a_2\times\times a_{n-1}\times b_nmb1​a1​b2​⋅⋅⋅a1​a2​⋅⋅⋅an−1​bn​, 上述公式可以提取公共乘项aia_iai​,写成m(bnbn−1⋅⋅⋅…

一文搞懂内存映射原理及使用方法

a. 内存映射原理内存映射即在进程的虚拟地址空间中创建一个映射,分为两种:文件映射:文件支持的内存映射,把文件的一个区间映射到进程的虚拟地址空间,数据源是存储设备上的文件。匿名映射:没有文件支持的内存…