
文章列表


<p><span style="white-space: pre; white-space-collapse: collapse;"> </span></p><p>我决定写的大部分内容都是由我认为我想阅读或被告知的内容驱动的。反思和收获是本博客所有内容的共同主题。这篇文章也不例外,也是我一直在考虑的事情。</p><p>挑选一些课程并将它们标记为最重要的课程并不容易,尤其是当您的第一份工作每天都会向您抛出新东西时。尽管如此,这是我试图浓缩所有这些信息,并提供我们在开始第一个软件角色之前不太可能听到的事情的一瞥。</p><p>测试:单元、集成和数以百万计的其他</p><p>编写代码只是冰山一角。还有很多其他的东西伴随着它。在DevOps和越来越多的跨职能角色和团队的世界里,你将花费大量时间(有时是令人讨厌的大量时间)来监控构建、应用程序运行状况以及本节的主题:编写测试。</p><p>并不是说我们中的许多人不知道这个概念,或者我们没想到会这样做<span style="color: #6a9955;">;我们只是没有意识到这是一个多么恒定的过程,以及它有时是多么令人惊讶的混乱。</span></p><p>以下是您应该知道的一些事项</p><p>有许多不同类型的测试,但每个软件开发人员最终可能会编写一些常见的测试,包括单元测试、集成测试和验收测试。在不赘述细节的情况下,每个类分别测试一个类、多个类和完整的端到端应用程序。过度简化:您单独测试应用程序的每个部分,然后将它们放在一起并确保它也能正常工作。</p><p>理想情况下,编写测试本身并不是一项任务<span style="color: #6a9955;">;相反,它是每项任务的关键部分。当你编写一段代码时,你也应该为它编写测试。</span></p><p>代码库质量的一个重要衡量标准是测试“覆盖率”。它表示至少一个测试覆盖了代码库的百分比。如果测试未涵盖您引入的新代码段,则您的拉取请求 (PR) 可能不会合并。或者,如果总体覆盖率低于阈值。这种检查大多是自动化的,例如以声纳门的形式。底线:这不是你通常可以扭动的东西!</p><p>撇开所有笑话不谈,测试在一天结束时确实起到了重要的作用,这解释了对它们的重视。特别是从初学者软件开发人员的角度来看,它让你重新思考你编写的代码,它应该让你评估诸如</p><p>这个功能的核心目的是什么</p><p>有没有更好的方法可以做到这一点</p><p>如何处理和测试边缘情况?</p><p>对于那些在大学里来自非 CS 背景的人,或者没有将其作为课程的一部分,您可能想阅读基础知识。</p><p>Git:不熟悉的部分</p><p>Git 和 VCS(版本控制系统)是不费吹灰之力的。每个人都知道这一点,与编写测试不同,这是我们大多数人在大学或从事个人项目时都接触过的东西。</p><p>不过,本节重点介绍在小型团队中工作时较少使用的 Git 部分,但在作为大型组织的一部分工作时,这些部分会成为日常工作中必不可少的方面。但是,请注意,这些是我的首选,最能帮助您进入第一个角色,并且您可以学到更多。</p><p>藏匿</p><p>当你意识到你需要对另一个分支的 PR 进行一两个快速评论时,你正在对一个分支进行更改。那么,如何在切换分支之前按下暂停键并保存更改呢?到目前为止,提交更改可能不是最佳选择,因为您不希望在提交历史记录中显示半成品代码存根。这很简单:只需隐藏您的更改即可。</p><p>git stash</p><p>当你想把它拿回来时</p><p>git stash pop</p><p>创建/应用修补程序</p><p>这个相当常见,但仍然值得一提。如果您要复制粘贴整个文件以与队友共享最新更改,请不要这样做。有一个概念是为此创建一个 Git 补丁。它会捕获您的更改。</p><p>不要让你对键盘和终端的热爱阻止你使用 IDE 的 UI(尤其是 IntelliJ)提供的快速 Git 操作。有时,这可能是完成某事的最快、最干净的方式。</p><p>cherry-pick</p><p>假设您想有选择地选择不同分支上的提交,并将它们应用于另一个分支。拉取更改并不是 git 提供的全部!</p><p>虽然期望使用和熟悉所有这些功能是不合理的,但至少将 Git 用于一些项目(您与团队的宠物项目,或者更好的是,在黑客马拉松中),并尝试它的许多功能可能会很好。</p><p>历史</p><p>唾手可得的果实,但尝试检查分支上的 git 历史记录/日志,并可能跟踪提交。</p><p>git log</p><p>CI/CD、生命周期和部署工具</p><p>正如我之前提到的,编码只是你最终必须做的事情的一部分。人们非常重视编写代码,大多数人都在DSA上狂热地在编码面试中取得好成绩。虽然这没关系,但我认为了解实际软件开发所需的其他事情也很好:一个主要主题是 CI/CD(持续集成、持续交付和部署)和常用工具。同样,没有必要使用这些来积累经验,但最好阅读一下它们。</p><p>说到实际的开发,没有什么比黑客马拉松更能让我做好准备的了。我鼓励每个有抱负的开发人员,或者任何想从事技术工作的人,在大学期间至少参加一次。(不同帖子的素材?</p><p>建立人脉,寻求帮助</p><p>与我之前谈到的技术部分不同,但我只需要把它放在这里。</p><p>这不仅仅是霍格沃茨,在大多数地方都是如此。大声说出来,不要回避问你可能有的问题——你应该有很多问题。这是学习和融入文化的最简单方法。如果您担心被评判,请不要这样做。大多数人都非常乐于助人,坐着妈妈比问很多问题要多得多。话虽如此,自学和探索内部文档和内容同样重要。</p><p>寻求帮助,但也要求指向文档/有用的存储库/内部网站和内容的方向,这样您就可以继续自己学习,这是一种两全其美的方法。</p><p>网络,你可能已经读过很多遍了。我了解到,有效的网络可以改变你在公司内如何看待自己,以及其他人如何看待你。</p><p>在软件工程这样的角色中,很容易错过 Scrum 团队之外的互动,但通过这些互动可以获得很多好处。</p><p>与来自不同角色、经验水平和地区的不同人谈。</p><p>活动和比赛是一个很好的起点。(此外,它们很有趣<span style="color: #6a9955;">;加上谁不喜欢在:)中奖)</span></p><p>如果有机会进行面对面的互动,请抓住它。我自己就是一个双面性格的人,很多社交互动并不是我一直喜欢的事情,但每隔一段时间就会有很多有趣的对话,错过会很可惜。</p><p><br/></p>

<p><span style="text-wrap: nowrap;">计算机经典编程书籍、大黑书、编程电子书、电子书、编程书籍,包括计算机基础、C/C++、Java、Python、面试题、架构设计、算法系列等经典电子书。</span></p><p><span style="text-wrap: nowrap;">信息时代,网络上充斥着各种资源。给同学们带来选择的同时,也带来了很多干扰。</span></p><p><span style="text-wrap: nowrap;">作为一名互联网/IT从业人员,经常需要搜索一些书籍、资源,在这个过程中踩过很多坑、浪费过很多时间。</span></p><p><span style="text-wrap: nowrap;">为了方便大家,我特意把这些年收集的计算机类书籍共享给大家。</span></p><p><span style="text-wrap: nowrap;">涵盖范围包括但不限于:C/C++、Python、Go、Linux、JavaScript、Rust等等。</span></p><p><br/></p><p><span style="text-wrap: nowrap;">C语言PDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">C++PDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">PythonPDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">JavaPDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">GOPDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">PHPPDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">vuePDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">cssPDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">QtPDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">JavascripPDF下载t、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">数据库PDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">Linux&UnixPDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">数据结构与算法PDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">设计模式PDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">服务器运维PDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">架构师PDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">计算机网络PDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">操作系统PDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">网络安全PDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">软件工程PDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">软件测试PDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">视觉智能PDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">人工智能PDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">matlabPDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">机器学习PDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">游戏编程PDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">数学与编程PDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">并行&并发PDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">嵌入式&硬件PDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">组成原理&底层PDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;">校招社招面试PDF下载、PDF在线阅读</span></p><p><span style="text-wrap: nowrap;"></span></p><hr/><p>由于pdf书籍数量过于庞大,这里不便一一列出,感兴趣的小伙伴自行在码小课在线阅读,或者下载到本地收藏。<br/><span style="text-wrap: nowrap;"></span></p><p>下面列出了部分PDF书籍的截图,有图有真相。</p><p>全部pdf数量统计:</p><p><img src="/uploads/images/20240108/b668a2fa7c140fd6f8be41503a4ccd4b.png" title="pdf原文件数量统计.png" alt="" width="556" height="353"/></p><p>pdf书籍分类查找页面:</p><p><img src="/uploads/images/20240108/00a9624fca903a615f12b21c0bd37df1.png" title="pdf网站分类页.png" alt="" width="992" height="620"/></p><p><br/></p><p>pdf在线阅读页面:</p><p><img src="/uploads/images/20240108/f4bd93ae977229a3887d89683da8cc61.png" title="pdf网站阅读页.png" alt="" width="1005" height="503"/></p><p><br/></p><p>pdf书籍在线阅读页面:</p><p><img src="/uploads/images/20240108/3c44028381b482b72f8dd36eef291851.png" title="pdf在线阅读目录页.png" alt="" width="812" height="531"/></p><p><br/></p>

<p>数学中我们学习了列方程式和解方程式。例如,y=2x方程中的x和y就是变量,代表某个数值:当x=1时,y的值就是2;当x=3时,y的值就是6。</p><p>Java中也有变量的概念,它也代表某个数值。例如,变量age代表年龄值,变量name代表姓名值。如果从计算机存储的角度来说,变量实质上就是内存中的一块数据存储区域,该区域有自己的名称(变量名)和类型(数据类型),Java中的每个变量都必须先声明后使用,该区域的数据可以在同一类型范围内不断变化。</p><p>Java的变量包含三个要素,分别是数据类型、变量名和变量值。数据类型决定了这个变量中要存储的数据值的类型及这块内存的宽度,如存储一个整数10和存储一个小数1.5在内存中所需要的宽度与存储方式是不同的。变量名就是一个标识符,方便在程序中使用。变量值就是这个变量具体存储的值。例如,“int age=18;”这个语句说明了age变量的数据类型是整型int,存储的值是18。</p><h2>3.3.1 变量的声明与使用</h2><p>变量的使用步骤可以具体分为声明、赋值、使用三步,下面是这三个步骤的详细介绍。</p><p><strong>1.声明</strong></p><p>变量的声明相当于向JVM申请一部分指定数据类型大小的内存。不同的数据类型,需要占用的内存大小是不同的。另外,JVM中每字节的内存都有自己的编号,称为内存地址,但是在程序中直接使用内存地址是极其不方便的,因此需要给这部分内存命名,方便在程序中对这部分内存进行访问和使用。变量声明如图3-3所示。<strong><br/></strong></p><p><img src="/uploads/images/20231205/d5c0f2c782059f08a7e653e2a5a1ce04.png" title="1.png" alt=""/></p><p>int是表示整数的数据类型,常见的数据类型说明如表3-3所示。</p><p><img src="/uploads/images/20231205/fb6e1b49024ff4786d26e4436670e6ba.png" title="1.png" alt="" width="624" height="129"/></p><p><strong>2.赋值</strong></p><p>将符号“=”右边的值放到对应的内存中。变量赋值如图3-4所示。<strong><br/></strong></p><p><img src="/uploads/images/20231205/33d61bdd86d24a1cbbc95edae94d9560.png" title="1.png" alt=""/></p><p><strong>3.使用</strong></p><p>所谓使用,是指在变量的作用域内将变量中的值拿出来进行打印、运算、比较等。示例代码:</p><p><strong><img src="/uploads/images/20231205/6eaa449711a16a7e82d8605426c0c43f.png" title="1.png" alt="" width="645" height="176"/></strong></p><p><strong>3.3.2 变量的注意事项</strong></p><p>1.必须先声明再使用</p><p>2.变量必须在初始化后才能使用<br/></p><p>3.变量有作用域,并且在同一个作用域中不可以重复命名</p><p>4.变量的值可以变化,但必须在变量声明的数据类型范围内</p><p style="text-wrap: wrap;"><span style="text-wrap: nowrap;">-------------------------------------------------------------------------</span></p><p style="text-wrap: wrap;"><span style="text-wrap: nowrap;">学习更多专业Java知识,点此查看:</span></p><p style="text-wrap: wrap;"><a href="https://www.maxiaoke.com/manual/springboot_hxjs.html" target="_self"><span style="text-wrap: nowrap;">《手把手带你学习SpringBoot-零基础到实战》</span></a></p><p style="text-wrap: wrap;"><img src="https://www.maxiaoke.com/uploads/images/20230627/b702bf7780c048d3ca8fc11bee9de654.jpg" title="SpringBoot.jpg" alt=""/></p><p style="text-wrap: wrap;"><span style="text-wrap: nowrap;">-------------------------------------------------------------------------</span></p><p><br/></p>

<p>高级编程语言由一系列单词和符号组成,并且能与计算机进行交互,实现逻辑功能。为了让程序员与计算机能够进行更好的交互,会提前给一些单词赋予特殊的含义,这些在程序语言中具有特殊含义的单词叫作关键字。其中有一部分关键字在Java中并没有使用,暂时没有赋予特殊含义,这部分称为保留字。</p><h2>1.Java中的关键字</h2><p>Oracle官网提供的Java语言规范之Java SE 8版——The Java® Language Specification Java SE 8 Edition中列出了所有关键字(含保留字),加起来共有50个单词,如图3-1所示。当然在之后的版本中,根据语法的需要,可能会增加新的关键字,如sealed、record等。</p><p><img src="/uploads/images/20231205/a6e65f8ea202abf6230da0b537539dd4.png" title="1.png" alt="" width="792" height="319"/></p><p>关键字是被Java语言赋予特殊含义,具有特殊用途的字符串(单词),如表3-1所示。关键字有一个特点是所有字母都为小写形式,关键字在后面的学习中会依次展开讲解,学习初期不用强行记忆。</p><p><img src="/uploads/images/20231205/85c5a134d09b6fa45d635e284244f9ed.png" title="1.png" alt="" width="693" height="391"/></p><h2>2.Java中的保留字</h2><p>在关键字中,还有一些单词在Java中没有正式使用,但是为了Java与底层系统(如C语言)的交互,Java保留了一些关键字,称为保留字。目前,保留字有如下两个。</p><p>(1)goto。goto语句在其他语言中叫作“无限跳转”语句。Java语言不再使用goto语句,这是因为goto语句会破坏程序结构。在Java语言中可以通过break、continue和return实现“有限跳转”。</p><p>(2)const。const在其他语言中是声明常量的关键字,在Java语言中使用final方式声明常量。</p><h2>3.Java中的特殊值</h2><p>Oracle官网提供的Java语言规范之Java SE 8版——The Java® Language Specification Java SE 8 Edition中特别说明了三个特殊值:true、false、null。这三个特殊值看起来像是关键字,但实际上是字面量值。后面在给标识符命名时,同样要避开使用特殊值。</p><p><span style="text-wrap: nowrap;">-------------------------------------------------------------------------</span></p><p><span style="text-wrap: nowrap;">学习更多专业Java知识,点此查看:</span></p><p><a href="https://www.maxiaoke.com/manual/springboot_hxjs.html" target="_self"><span style="text-wrap: nowrap;">《手把手带你学习SpringBoot-零基础到实战》</span></a></p><p><img src="/uploads/images/20230627/b702bf7780c048d3ca8fc11bee9de654.jpg" title="SpringBoot.jpg" alt=""/></p><p><span style="text-wrap: nowrap;">-------------------------------------------------------------------------</span></p><p><br/></p>

<p>关系型数据库典型的数据结构是表,数据库是由二维表及其之间的联系所组成的一个数据组织。关系型数据库的优点体现在以下几个方面:</p><p>易于维护:都是使用表结构,格式一致。</p><p>使用方便:SQL语言通用,可用于复杂查询。</p><p>复杂操作:支持SQL,可用于一个表以及多个表之间非常复杂的查询。</p><p>不过关系型数据库也存在以下几个方面的缺点:</p><p>读写性能比较差,尤其是海量数据的高效率读写。</p><p>固定的表结构,灵活度稍微欠缺。</p><p>高并发读写需求,对传统关系型数据库来说,硬盘I/O是一个很大的瓶颈。</p><p>Python作为一种主流的编程语言,提供了对关系型数据库的支持。</p><p>SQLite 3可使用sqlite3模块与Python进行集成。sqlite3模块是由Gerhard Haring编写的。该模块提供了一个与PEP 249描述的DB-API 2.0规范兼容的SQL接口。用户不需要单独安装该模块,因为Python 3.x版本默认自带了该模块。</p><p>要使用数据库,首先需要连接到数据库。调用SQLite3的connect()方法即可连接到指定数据库,其语法格式如下:</p><pre class="brush:as3;toolbar:false"> sqlite3.connect(database [,timeout ,other optional arguments])</pre><p>其中,参数database即为需要连接的目标数据库;参数timeout为指定超时设置;参数other optional arguments为其他参数设置。执行该方法将会连接到指定数据库,如果数据库不存在,就尝试创建一个。</p><p><img src="/uploads/images/20231204/307b38b8fa2e9dc2d2d0b2247c88fd48.png" title="1.png" alt=""/></p><p>以上代码调用connect()方法对指定数据库进行连接,并在成功连接后输出相应内容。将以上代码保存为3-13.py,执行以上代码,其结果将会如图3-13所示,并且会在当前目录下生成名为my_db.db的数据库文件。</p><p>表是构成数据库的基本单元,连接数据库之后,就需要在数据库中创建表。要创建表,首先需要调用connection对象的cursor()方法创建一个游标(cursor)对象。然后调用游标对象的execute()方法执行建表的语句,在数据库中创建表。该方法的语法格式如下:</p><pre class="brush:as3;toolbar:false"> cursor.execute(sql [, optional parameters])</pre><p><img src="/uploads/images/20231205/c25485e30276496850ac2004b7bb0025.png" title="1.png" alt="" width="940" height="273"/></p><p>以上代码调用cursor()方法创建一个游标,然后调用execute()方法执行创建表的SQL语句,最后调用commit()方法提交建表操作。执行以上代码将会在当前my_db.db数据库中创建一个名为USER的表。</p><p>成功创建表之后,就需要向表中插入数据。仍然是调用游标对象的execute()方法执行插入数据的SQL语句,并在执行之后调用commit()方法提交这些操作,就可以实现向表中插入数据。</p><p><img src="/uploads/images/20231205/d2c346fc0ac84a16c400e3c7a82c2cd4.png" title="1.png" alt="" width="928" height="293"/></p><p>以上代码通过execute()方法执行SQL语句向表中插入数据。</p><p>执行遍历表中所有信息的语句即可实现浏览表中记录的功能,同样是执行execute()方法,执行相应的SQL语句即可。</p><pre class="brush:as3;toolbar:false"> import sqlite3 as sql con=sql.connect("my_db.db") c=con.cursor() rows=c.execute("SELECT * FROM USER") for r in rows: print("ID = ", r[0]) print("NAME = ", r[1]) print("ADDRESS = ", r[2]) print("SALARY = ", r[3], "\n") con.close()</pre><p>以上代码通过execute()方法执行遍历所有记录的SQL语句以执行浏览数据的操作,然后通过for遍历所有结果集,并将内容输出。</p><p style="text-wrap: wrap;"><span style="text-wrap: nowrap;">---------------------------------------------------------------------------------</span></p><p style="text-wrap: wrap;"><span style="text-wrap: nowrap;">学习更多专业Python知识,点此查看:</span></p><p style="text-wrap: wrap;"><a href="https://www.maxiaoke.com/manual/py_ssz.html" target="_self"><span style="text-wrap: nowrap;">《剑指Python-上》</span></a><span style="text-wrap: nowrap;"> </span><a href="https://www.maxiaoke.com/manual/jz_pys_2.html" target="_self"><span style="text-wrap: nowrap;">《剑指Python-下》</span></a></p><p style="text-wrap: wrap;"><img src="https://www.maxiaoke.com/uploads/images/20231204/a64aeb23219a212638811c5bd0f355b0.png" title="py小册封面.png" alt=""/></p><p style="text-wrap: wrap;"><span style="text-wrap: nowrap;">---------------------------------------------------------------------------------</span></p><p><br/></p>

<p>文件是存储数据的基本载体,对文件的操作几乎是所有编程语言都会涉及的内容。而使用Python进行爬虫操作,进行数据的解析,文件操作也是必不可少的内容。本节就先来学习一下文件的存储。</p><p>3.1.1 TXT文件存储</p><p>TXT文件即文本文件,是一种简单的文件类型,用户可以将数据写入文本文件中,在使用时直接读取文件内容即可。Python支持将数据写入文本文件中,在需要使用时可以使用特定方法直接读取。下面就来详细介绍在Python中如何将数据写入文本文件中,以及如何读取。</p><p>使用Python来读写文件是非常简单的操作。可以调用Python自带的open()函数来打开一个文件,获取到文件句柄,然后通过文件句柄就可以进行各种各样的操作。</p><pre class="brush:as3;toolbar:false"> open(name[, mode[, buffering]])</pre><p>其中,参数name为指定需要打开的文件的名称;参数mode为打开的方式,根据打开方式的不同可以进行不同的操作;参数buffering用于指定打开文件时是否寄存。如果buffering取值为0,就不会有寄存;如果buffering取值为1,访问文件时就会寄存;如果将buffering的值设为大于1的整数,就表明这是寄存区的缓冲大小;如果buffering取负值,寄存区的缓冲大小就为系统默认值。</p><p>调用open()函数打开文件之后,还需要以下file对象的方法来配合实现对文件的读取操作</p><p>下面将通过一组实例说明如何调用open()函数及file对象的方法来实现对文件的读取操作。</p><p>首先将以下文本内容保存为test.txt。</p><p><img src="/uploads/images/20231204/e969f64c3707560b1a068e879a2e5333.png" title="1.png" alt="" width="665" height="270"/></p><p>【示例3-1】读取文件内容</p><p><img src="/uploads/images/20231204/e39e9a7812601a8490e73acf1d5ecbbb.png" title="1.png" alt="" width="668" height="72"/></p><p>以上代码调用open()函数打开文件,然后调用read()方法读取文件内容,并将文件内容输出,最后关闭文件。将以上代码保存为3-1.py,执行该代码的结果如图3-1所示。</p><p><img src="/uploads/images/20231204/ff95394ea4afc4cef9ca91d5ff470ce8.png" title="1.png" alt=""/></p><p style="text-wrap: wrap;"><span style="text-wrap: nowrap;">---------------------------------------------------------------------------------</span></p><p style="text-wrap: wrap;"><span style="text-wrap: nowrap;">学习更多专业Python知识,点此查看:</span></p><p style="text-wrap: wrap;"><a href="https://www.maxiaoke.com/manual/py_ssz.html" target="_self"><span style="text-wrap: nowrap;">《剑指Python-上》</span></a><span style="text-wrap: nowrap;"> </span><a href="https://www.maxiaoke.com/manual/jz_pys_2.html" target="_self"><span style="text-wrap: nowrap;">《剑指Python-下》</span></a></p><p style="text-wrap: wrap;"><img src="https://www.maxiaoke.com/uploads/images/20231204/a64aeb23219a212638811c5bd0f355b0.png" title="py小册封面.png" alt=""/></p><p style="text-wrap: wrap;"><span style="text-wrap: nowrap;">---------------------------------------------------------------------------------</span></p><p><br/></p>

<p>在进行网络爬虫时,经常会提到“代理”一词,那么究竟什么是代理?代理服务器是如何进行工作的?代理有什么作用?如何对代理服务进行设置?这一节就来解决这些问题。</p><p>2.5.1 基本原理</p><p>首先来看什么是代理。代理实际上指的就是代理服务器(Proxy Server),它的功能是代理网络用户获取网络信息。形象地说,代理服务器就是网络信息的中转站。</p><p>在用户正常请求一个网站时,发送了请求给Web服务器,Web服务器把响应传回给用户。如果设置了代理服务器,实际上就是在本机和服务器之间搭建了一个桥,此时本机不是直接向Web服务器发起请求,而是向代理服务器发起请求,请求会发送给代理服务器,然后由代理服务器再发送给Web服务器,接着由代理服务器把Web服务器返回的响应转发给本机。</p><p>这样用户同样可以正常访问网页,但在这个过程中,Web服务器识别出的真实IP就不再是用户本机的IP了,成功实现了IP伪装,这就是代理的基本原理。</p><p>2.5.2 代理的作用</p><p>(1)代理可以突破自身IP访问限制,访问一些平时不能访问的站点。比如网上常说的翻墙、科学上网之类就是使用了代理技术。</p><p>(2)使用代理可以访问一些单位或团体的内部资源。比如使用的如果是教育网内地址段的免费代理服务器,就可以对教育网开放各类FTP下载、上传,以及各类资料查询、共享等服务。</p><p>(3)使用代理可以提高访问速度。通常代理服务器都会设置一个较大的硬盘缓冲区,当有外界的信息通过时,同时也会将其保存到缓冲区中,当其他用户再访问相同的信息时,则直接从缓冲区中取出信息传给用户,以提高访问速度。</p><p>(4)使用代理可以隐藏真实IP。上网者可以通过代理服务隐藏自己的IP,进而免受攻击。对于爬虫来说,使用代理就是为了隐藏自身IP,防止自身的IP被封锁。因为通常大数据量的访问会引起对方主机的怀疑,从而有可能造成封锁IP的访问权限。</p><p>2.5.3 代理分类</p><p>按照代理不同的分类标准,可以对代理进行不同的分类,既可以根据协议区分,又可以根据其匿名程度区分。</p><p>(1)FTP代理服务器:主要用于访问FTP服务器,一般有上传、下载以及缓存功能,端口一般为21、2121等。</p><p>(2)HTTP代理服务器:主要用于访问网页,一般有内容过滤和缓存功能,端口一般为80、8080、3128等。</p><p>(3)SSL/TLS代理:主要用于访问加密网站,一般有SSL或TLS加密功能(最高支持128位加密强度),端口一般为443。</p><p>(4)RTSP代理:主要用于访问Real流媒体服务器,一般有缓存功能,端口一般为554。</p><p>(5)Telnet代理:主要用于Telnet远程控制(黑客入侵计算机时常用于隐藏身份),端口一般为23。</p><p>(6)POP3/SMTP代理:主要用于POP3/SMTP方式收发邮件,一般有缓存功能,端口一般为110/25。</p><p>(7)SOCKS代理:只是单纯传递数据包,不关心具体协议和用法,所以速度快很多,一般有缓存功能,端口一般为1080。SOCKS代理协议又分为SOCKS 4和SOCKS 5,前者只支持TCP,而后者支持TCP和UDP,还支持各种身份验证机制、服务器端域名解析等。简单来说,SOCK 4能做到的SOCKS 5都可以做到,但SOCKS 5能做到的SOCK 4不一定能做到。</p><p>根据代理的匿名程度,代理可以分为如下类别:</p><p>(1)高度匿名代理:会将数据包原封不动地转发,在服务端看来就好像真的是一个普通的客户端在访问,而记录的IP是代理服务器的IP。</p><p>(2)普通匿名代理:会在数据包上做一些改动,在服务端上有可能发现这是一个代理服务器,也有一定概率追查到客户端的真实IP。代理服务器通常会加入的HTTP头有HTTP_VIA和HTTP_X_FORWARDED_FOR。</p><p>(3)透明代理:不但改动了数据包,还会告诉服务器客户端的真实IP。这种代理除了能用缓存技术提高浏览速度、能用内容过滤提高安全性之外,并无其他显著作用,常见的例子是内网中的硬件防火墙。</p><p>(4)间谍代理:指组织或个人创建的用于记录用户传输的数据,然后进行研究、监控等的代理服务器。</p><p>2.5.4 常见代理设置</p><p>常见的代理设置有以下几种:</p><p>(1)使用网上的免费代理。这种情况最好使用高匿代理,另外可用的代理不多,需要在使用前筛选一下可用代理,也可以进一步维护一个代理池。</p><p>(2)使用付费代理服务。互联网上存在许多代理商,可以付费使用,质量比免费代理好很多,而且速度更快,也更稳定,不过需要支付相应代理服务费。</p><p>(3)使用ADSL拨号。拨一次号换一次IP,稳定性高,是一种比较有效的解决方案。</p><p style="text-wrap: wrap;"><span style="text-wrap: nowrap;">---------------------------------------------------------------------------------</span></p><p style="text-wrap: wrap;"><span style="text-wrap: nowrap;">学习更多专业Python知识,点此查看:</span></p><p style="text-wrap: wrap;"><a href="https://www.maxiaoke.com/manual/py_ssz.html" target="_self"><span style="text-wrap: nowrap;">《剑指Python-上》</span></a><span style="text-wrap: nowrap;"> </span><a href="https://www.maxiaoke.com/manual/jz_pys_2.html" target="_self"><span style="text-wrap: nowrap;">《剑指Python-下》</span></a></p><p style="text-wrap: wrap;"><img src="https://www.maxiaoke.com/uploads/images/20231204/a64aeb23219a212638811c5bd0f355b0.png" title="py小册封面.png" alt=""/></p><p style="text-wrap: wrap;"><span style="text-wrap: nowrap;">---------------------------------------------------------------------------------</span></p><p><br/></p>

<p>2.4 会话和Cookies</p><p>Cookie是一小段文本信息,伴随着用户请求和页面在Web服务器和浏览器之间传递。用户每次访问站点时,Web应用程序都可以读取Cookie包含的信息。Cookie的基本工作原理:如果用户再次访问站点上的页面,当该用户输入URL地址时,浏览器就会在本地硬盘上查找与该URL相关联的Cookie。如果该Cookie存在,浏览器就将它与页面请求一起发送到用户请求的站点。Cookie根本的用途是:Cookie能够帮助Web站点保存有关访问者的信息。更简单地说,Cookie是一种保持Web应用程序连续性(执行“状态管理”)的方法。</p><p>什么是会话(Session)?当用户访问站点时,服务器会为该用户创建唯一的会话,会话将一直延续到用户访问结束。</p><p>2.4.1 静态网页和动态网页</p><p>静态网页的网址形式通常是以.htm、.html、.shtml、.xml等为后缀的。静态网页一般来说是最简单的HTML网页,服务器端和客户端是一样的,而且没有脚本和小程序,所以它不能动。在HTML格式的网页上,也可以出现各种动态的效果,如.gif格式的动画、FLASH、滚动字母等,这些“动态效果”只是视觉上的,与后面将要介绍的动态网页是不同的概念。</p><p>静态网页有以下特点:(1)静态网页每个网页都有一个固定的URL,且网页URL以.htm、.html、.shtml等常见形式为后缀,而不含有“?”。</p><p>(2)网页内容一经发布到网站服务器上,无论是否有用户访问,每个静态网页的内容都是保存在网站服务器上的,也就是说,静态网页是实实在在保存在服务器上的文件,每个网页都是一个独立的文件。</p><p>(3)静态网页的内容相对稳定,因此容易被搜索引擎检索。</p><p>(4)静态网页没有数据库的支持,在网站制作和维护方面工作量较大,因此当网站信息量很大时,完全依靠静态网页制作方式比较困难。</p><p>(5)静态网页的交互性较差,在功能方面有较大的限制。</p><p>动态网页是以.asp、.jsp、.php、.perl、.cgi等形式为后缀的,并且在动态网页网址中有一个标志性的符号“?”。动态网页与网页上的各种动画、滚动字幕等视觉上的“动态效果”没有直接关系,动态网页可以是纯文字内容,也可以是包含各种动画的内容,这些只是网页具体内容的表现形式,无论网页是否具有动态效果,采用动态网页技术生成的网页都称为动态网页。动态网页也可以采用静动结合的原则,适合采用动态网页的地方采用动态网页,如果需要使用静态网页,就可以考虑用静态网页的方法来实现,在同一个网站上,动态网页内容和静态网页内容同时存在是很常见的事情。</p><p>动态网页具有以下特点:</p><p>(1)交互性,即网页会根据用户的要求和选择而动态改变和响应。例如,访问者在网页上填写表单信息并提交,服务器经过处理将信息自动存储到后台数据库中,并打开相应提示页面。</p><p>(2)自动更新,即无须手动操作,便会自动生成新的页面,可以大大节省工作量。例如,在论坛中发布信息,后台服务器将自动生成新的网页。</p><p>(3)随机性,即当不同的时间、不同的人访问同一网址时会产生不同的页面效果。例如,登录界面自动循环功能。</p><p>(4)动态网页中的“?”对搜索引擎检索存在一定的问题,搜索引擎一般不可能从一个网站的数据库中访问全部网页,或者出于技术方面的考虑,搜索蜘蛛不会去抓取网址中“?”后面的内容,因此采用动态网页的网站在进行搜索引擎推广时,需要做一定的技术处理才能适应搜索引擎的要求。</p><p>静态网页和动态网页各有特点,网站采用动态网页还是静态网页主要取决于网站的功能需求和网站内容的多少,如果网站功能比较简单,内容更新量不是很大,采用纯静态网页的方式会更简单,如果网站功能复杂,那么最好采用动态网页技术来实现。</p><p>2.4.2 无状态HTTP</p><p>HTTP(Hyper Text Transport Protocol,超文本传输协议)是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,它就必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时,它的应答就较快。</p><p>客户端与服务器进行动态交互的Web应用程序出现之后,HTTP无状态的特性严重阻碍了这些应用程序的实现,毕竟交互是需要承前启后的,简单的购物车程序也要知道用户到底在之前选择了什么商品。于是,两种用于保持HTTP连接状态的技术就应运而生了,一个是Cookie,另一个则是Session。</p><p>Cookie是通过客户端保持状态的解决方案。从定义上来说,Cookie就是由服务器发给客户端的特殊信息,这些信息以文本文件的方式存放在客户端,然后客户端每次向服务器发送请求的时候都会带上这些特殊的信息。讲得更具体一些:当用户使用浏览器访问一个支持Cookie的网站的时候,用户会提供包括用户名在内的个人信息并且提交至服务器;接着,服务器在向客户端回传相应的超文本的同时也会发回这些个人信息,当然这些信息并不是存放在HTTP响应体中的,而是存放于HTTP响应头中的;当客户端浏览器接收到来自服务器的响应之后,浏览器会将这些信息存放在一个统一的位置。对于Windows操作系统而言,我们可以从:</p><pre class="brush:as3;toolbar:false">[系统盘]:\Documents and Settings\[用户名]\Cookies</pre><p>目录中找到存储的Cookie。自此,客户端再向服务器发送请求的时候,都会把相应的Cookie再次发回至服务器。而这次,Cookie信息则存放在HTTP请求头中。</p><p>有了Cookie这样的技术实现,服务器在接收到来自客户端浏览器的请求之后,就能够通过分析存放于请求头的Cookie得到客户端特有的信息,从而动态生成与该客户端相对应的内容。通常,我们可以从很多网站的登录界面中看到“请记住我”这样的选项,如果你勾选了该选项之后再登录,那么在下一次访问该网站的时候就不需要进行重复而烦琐的登录动作了,这个功能就是通过Cookie实现的。</p><p>与Cookie相对的一个解决方案是Session,它是通过服务器来保持状态的。由于Session这个词汇包含的语义很多,因此需要在这里明确一下Session的含义。</p><p>首先,我们通常都会把Session翻译成会话,因此可以把客户端浏览器与服务器之间一系列的交互动作称为一个Session。从这个语义出发,我们会想到Session持续的时间,会提到在Session过程中进行了什么操作,等等。</p><p>其次,Session指的是服务器端为客户端所开辟的存储空间,在其中保存的信息就是用于保持状态的。从这个语义出发,我们会提到往Session中存放什么内容,如何根据键值从Session中获取匹配的内容,等等。</p><p>要使用Session,第一步当然是创建Session了。那么Session在何时创建呢?当然是在服务器端程序运行的过程中创建的,不同语言实现的应用程序有不同的创建Session的方法,而在Java中是通过调用HttpServletRequest的getSession方法(使用true作为参数)来创建的。在创建了Session的同时,服务器会为该Session生成唯一的Session ID,而这个Session ID在随后的请求中会被用来重新获得已经创建的Session;在Session被创建之后,就可以调用Session相关的方法往Session中增加内容了,而这些内容只会保存在服务器中,发送到客户端的只有Session ID;当客户端再次发送请求的时候,会将这个Session ID带上,服务器接收到请求之后就会依据Session ID找到相应的Session,从而再次使用。正是这样一个过程,用户的状态就得以保持了。</p><p>综上所述,HTTP本身是一个无状态的连接协议,为了支持客户端与服务器之间的交互,我们需要通过不同的技术为交互存储状态,而这些技术就是Cookie和Session。</p><p style="text-wrap: wrap;"><span style="text-wrap: nowrap;">---------------------------------------------------------------------------------</span></p><p style="text-wrap: wrap;"><span style="text-wrap: nowrap;">学习更多专业Python知识,点此查看:</span></p><p style="text-wrap: wrap;"><a href="https://www.maxiaoke.com/manual/py_ssz.html" target="_self"><span style="text-wrap: nowrap;">《剑指Python-上》</span></a><span style="text-wrap: nowrap;"> </span><a href="https://www.maxiaoke.com/manual/jz_pys_2.html" target="_self"><span style="text-wrap: nowrap;">《剑指Python-下》</span></a></p><p style="text-wrap: wrap;"><img src="https://www.maxiaoke.com/uploads/images/20231204/a64aeb23219a212638811c5bd0f355b0.png" title="py小册封面.png" alt=""/></p><p style="text-wrap: wrap;"><span style="text-wrap: nowrap;">---------------------------------------------------------------------------------</span></p><p><br/></p>

<p><strong>2.3.1 爬虫概述</strong></p><p>爬虫实际上就是采集网络上数据的一段程序。把这句话拆分一下,去掉其中的修饰词,就可以看到其实爬虫指的就是一段程序。这段程序的功能就是从网络上采集需要的数据。</p><p>一个爬虫的工作流程如下:</p><p>(1)发起请求。</p><p>(2)获取响应内容。</p><p>(3)解析内容。</p><p>(4)保存数据。</p><p>所以,爬虫就是从请求内容(即数据)到获取响应,接着解析内容,最后显示相应内容或者保持内容的过程。</p><p><strong>2.3.2 能抓取什么样的数据</strong></p><p>通过2.3.1小节的介绍,我们了解到爬虫的主要作用就是采集网络上的数据,那么究竟爬虫能抓取什么样的数据呢?从广义上来说,只要是能请求并且能获取响应的数据都能够被抓取,具体包括以下几类:</p><p>(1)网页文本,如HTML文档、JSON格式文本、XML格式文本等。</p><p>(2)图片文件,如JPEG、PNG等图片文件,获取的是二进制文件,保存为相应格式的图片即可。</p><p>(3)视频文件,如MP4、WMV等视频文件,同样获取的是二进制文件,保存为相应的视频格式即可。</p><p>(4)其他文件。只要是能请求到的文件都能获取,比如MP3文件、Flash文件以及其他各种类型的文件。</p><p><strong>2.3.3 JavaScript渲染页面</strong></p><p>在介绍JavaScript渲染页面之前,我们先来了解一下浏览器渲染页面的过程。HTML源代码由浏览器渲染为一个网页需要以下过程:<strong><br/></strong></p><p>(1)浏览器根据HTML结构生成DOM Tree(节点树)。</p><p>(2)浏览器根据CSS(Cascading Style Sheets,层叠样式表)生成CSSOM(样式表对象模型)。</p><p>(3)将DOM和CSSOM整合,形成RenderTree(渲染树)。</p><p>(4)浏览器根据渲染树开始渲染页面。</p><p>在这个过程中遇到<script>时会执行并阻塞渲染,因为JavaScript有权利改变DOM结构,甚至也能改变对象的CSS样式,所以要等JavaScript脚本执行完毕,之后再继续渲染过程。</p><p>通过以上内容可以了解到,JavaScript在整个页面渲染过程中起着举足轻重的作用,包括JavaScript在页面中的放置位置也十分重要。</p><p>如果JavaScript要对页面中的某个元素进行操作,就必须在这个元素加载之后才能进行,比如下面的代码。</p><p>【示例2-4】JavaScript渲染页面错误演示</p><pre class="brush:html;toolbar:false"><!DOCTYPE html> <html lang="zh-CN"> <head> <title>节点方法的调用</title> </head> <body> <script> obj=document.getElementById("my_div") alert(obj.innerHTML) </script> <div id="my_div">1234567</div> </body> </html></pre><p>以上代码尝试获取页面中层里的内容并以弹出窗口的形式显示其内容。将以上代码保存为2-6.htm,执行代码会发现,只会正常显示网页,但并没有任何弹出窗口。之所以会出现这种情况,就是因为<script>的出现中止了页面的渲染,导致获取不到<script>后面的层里的内容。</p><p>如果将代码修改如下:</p><pre class="brush:html;toolbar:false"><div id="my_div">1234567</div> <script> obj=document.getElementById("my_div") alert(obj.innerHTML) </script></pre><p>也就是将<script>放到要操作层之后,修改后将代码保存为2-7.htm,再次执行代码就会看到弹出窗口的提示,执行结果如图2-10所示。</p><p><img src="/uploads/images/20231204/3d4a5a722fb5d992a7a04d4a7c263974.png" title="1.png" alt="" width="693" height="344"/></p><p><br/></p><p>学习更多专业Python知识,点此查看:</p><p style="text-wrap: wrap;"><a href="https://www.maxiaoke.com/manual/py_ssz.html" target="_self">《剑指Python-初级》</a> <a href="https://www.maxiaoke.com/manual/jz_pys_2.html" target="_self">《剑指Python-高级》</a></p><p><img src="/uploads/images/20231204/a64aeb23219a212638811c5bd0f355b0.png" title="py小册封面.png" alt=""/></p><p><br/></p><p><br/></p>