0

前端程序员学python(爬虫向)(一文修到筑基期) (本文不含知识诅咒) - 加伊bky

 1 year ago
source link: https://www.cnblogs.com/Kay-Larry/p/17000866.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

我踏马来辣

还有一件事:

  1. 本教程配合c语言中文网 python爬虫 教程 食用
  2. 本教程不适用于未成年人
  3. 一定要刷牙
  4. 本教程不存在知识诅咒
  5. 学完本教程即可进入筑基期
  6. js 基础和本教程学习效率成正比
  7. 暂时不要驾驶你的行李箱
  8. 本教程是针对前端程序员制定的
  9. vscode是IDE大王,什么?你说vscode不是IDE?

令我惊喜的是 py和js有很多相似的地方 甚至作为一个前端程序员,在看到python代码的那一刻,倍感亲切

  • 都是脚本语言
  • 都有弱类型变量
  • 都不用写分号,当然也可以写
  • 都有自己的包管理库 py是 pip , js是 npm 参见 npm 和 pip 介绍

本来我觉得js已经够自由了,弱类型变量、以回车结束语句、简洁明了又极度自由的语法,而python代码则更为简洁

如果你也是正在学习Python的前端程序员,那么你一定跟我感同身受

py定义变量时甚至不需要 关键词 (js是 let var),这个东西甚至简洁到让我怀疑它是不是真的能用

可能写C++的人看到 js 代码也会有这种疑惑

相信看到这里,你和我有了一个共同的问题:既然简洁到这种程度,那我想定义一个常量该怎么办?牛逼的事情来了,python摒弃了常量这个东西,我觉得是py认为常量太不纯粹,我为什么需要一个不能修改的值?于是,python没有常量,如果你实在需要一个常量,也可以 通过其他方式实现

如果你的编程生涯也是从切图仔做起的,不懂什么数据结构、计算机原理、编译原理,那么你可能会对下面的代码产生疑惑

import urllib.request

和 js 相比较,这个写法简直奇怪到姥姥家了,主要的疑问有两点:1.我从没有下载过这个包,怎么引入成功了?2.我怎么知道哪些包可以引用?参见 Python是如何找包的,Python安装的包放在哪里 ,当然的然,没有下载过一个包,或者py没有自带这个包,也就是说,你本地没有这个包的情况下,也是不能引入的,只是py的解释器会自动在配置好的路径中去查找这个包。

就比如 在标准npm项目中 的使用import引入,会自动去node_modules中查找一样

在js中,我想实现某个相较复杂的功能,会先去npm上搜索有没有可用包,这是正常操作。在py中,也有类似的操作,且py能干的事情不再局限在web的前后端上,所以py的包几乎涵盖了所有领域,这也是py崛起的原因之一。作为一个py新手,如果你想实现一个功能,不妨先去pip上搜一下。

我看到的py爬虫教程,第一个程序是这么写的

import urllib.requestresponse = urllib.request.urlopen('http://www.baidu.com/')print(response)html = response.read().decode('utf-8')print(html)

显然,如果你有一点任何语言的基础,那么这几行代码根本不需要注释,py十分贴近自然语言,这也是我为什么选择py作为第二语言的原因。

对与上面的代码,需要注意的点有:

  1. 引入时不是以斜杠而是以点表示下级的,而且不需要引号或括号
  2. 定义变量不需要关键字 像上面的 response = 和 html = 都是变量的定义(py中可以直接叫赋值,因为其实就是赋值操作,如果想定义一个空变量可以使其 = null)
  3. 还可以这么写 from urllib import request (甚至接近中文表达方式,和es6相反)

本节教程:http://c.biancheng.net/python_spider/the-first-spider.html

再多一点点

半路出家的前端人,对网络协议、网络请求也知之甚少,要学习爬虫,对此要有进一步的了解。首先,各大网站都对爬虫做了一些限制,比如监测到爬虫频繁访问的话,有可能对该ip进行短时间的封锁,比如常见的:“操作频繁”提示,就是对ip的一种封锁,在前端的眼里,这个操作叫节流和防抖,在py爬虫上,叫做反爬。

网站对爬虫做出限制,其实是很好理解的,因为不同于普通的浏览器用户(真人),爬虫有能力大量频繁的访问,可能会对服务器造成负担。当然,也不是不希望爬虫去访问,相反的,很多网站其实是欢迎爬虫的,因为这有利于在百度等搜索引擎的关键词排名,也就是常常听说的SEO。总之就是一句话,想让你爬,但不想让你会会的爬,年轻人不要太气盛。

不气盛还叫年轻人吗?

我们知道,一个大型网站的访问的数量级是很大的,爬虫,多我一个不多,少我一个不少。我如果就想不断地、频繁的访问怎么办?User-Agent,用户代理。如果你玩手机时,在手机浏览器里曾经见过一个叫UA的选项,里面可以选择PC、Iphone、Android,那么恭喜你,因为你早就认识它了,网站反爬时,识别UA是一个基本手段。UA是一个字符串,可以告知你访问的网站你使用的的软件基本信息 参见 User-Agent(用户代理)是什么

不断地变换你的UA就可以达到欺骗反爬程序的效果。

本节教程 http://c.biancheng.net/python_spider/useragent-pool.html

自定义UA代理池,严先生(介绍一下,他是C语言中文网的站长,记住了,下面不再介绍了)为我们列举了几个常用的UA字符串,并把它放在了一个新建文件里。

问题来了,引入pip包我会了,但是自己建的文件我却不会,这没什么可担心的,这种事情一听就很基础,参见 python引入其他文件夹里的py文件的方法,引入后,接下来的你就会了。

严先生说了,我们要不断变换我们的UA值,那么我就想着取一个随机数,然后使用这个随机数作为数组的下标值,取出数据,于是我上网搜了:python随机数

看到了这样一个震惊的东西

  • random.choice(sequence):从特定序列中随机取一个元素,这里的序列可以是字符串,列表,元组等。

解释一下sequence:我也不懂,搜了一下,叫序列,应该跟数组是一种东西,注意,这个东西不是任何专业术语,这是个单词,python中的序列类型包括:list, tuple 和 range 对象。

关于python序列参见 https://blog.csdn.net/weixin_42214654/article/details/114411515

浅看一眼,我得知python中没有数组,和数组最类似的就是 list ,基本上等于js中的Array,但是稍微有点区别

参见 https://blog.csdn.net/weixin_30834019/article/details/97694533

综上所述,现在来综合试一下,文件引入,和随机取元素

import uaList #这是我自定义的那个文件import random #如果你没有引入这个东西,会自动提示引入的headers = { 'User-Agent': random.choice(uaList.ua_list)}

很显然,我写的没有问题,每次都能取到一个随机的值。

哎等会,现在发生了一件很奇怪的事情

image-20221206180212701

我干干净净的目录出现了一个命名方式令人抓狂的、不认识的、里边文件打不开的文件夹!能不能删除,我替你们试了,可以删,但是删掉之后一运行还会出来。关于这个文件,参见:pyhton中__pycache__文件夹的产生与作用

我们好像已经做了2178个词的准备了,但是学python好像不如我想象的那么迅速,我们写HTML下一秒就能看到效果,但是python好像不行,耐心点,我们应该马上可以学会了。

接下来需要了解的是 URL的编码和解码。

为什么URL还需要编码,编什么码,什么编码?在我的印象里,url就是网址,我只知道他是一个网址,或者叫链接,我也不知道怎么叫才是正规的。

URL 是由一些简单的组件构成,比如协议、域名、端口号、路径和查询字符串等,示例如下:

http://www.biancheng.net/index?param=10

显然 http是网络协议 冒号双斜杠不知道为什么要加,但我们都知道要加,后面的问号我们知道是用来分割网址和参数的,我们还知道使用&分割参数与参数。其余的不知道了。

那么此时可以联想到,上述几个符号:斜杠、冒号、问号、and符号 都是不能被作为正常的字符去解析的,他们被称为保留字,就像在js中,你不可以把一个变量命名为 let

image-20221207132532763

在url中,保留字需要转码,其次,就是不安全字符,像方括号、尖括号、双引号、大括号、分隔符等,还有,url是用的ASCII码,也就是说它不支持中文(我们知道支持中文的编码有 utf-8或者GBK,其他的不知道了),中文也需要转码!

等等,我是说,等一下,太多了,我怎么记得住?

没关系,要是我们在学别的语言,那确实太多了,但我们学的是python,python啊大哥,python的标准库中有自动编码的东西,他妈的,上边一通白说了,我们要快速面向业务!

Python实现编码与解码

Python 的标准库urllib.parse模块中提供了用来编码和解码的方法,分别是 urlencode() 与 unquote() 方法。

#导入parse模块from urllib import parse#构建查询字符串字典query_string = {'wd' : '爬虫'}#调用parse模块的urlencode()进行编码result = parse.urlencode(query_string)#使用format函数格式化字符串,拼接url地址url = 'http://www.baidu.com/s?{}'.format(result)print(url)#wd=%E7%88%AC%E8%99%AB#http://www.baidu.com/s?wd=%E7%88%AC%E8%99%ABresult = parse.unquote(url)print(result)#爬虫

好小子,白让我看这么多,有自动的我还学什么,现用现搜。

本节教程:URL编码/解码详解

做了2869个词的准备之后,我们终于要开始爬了。

明确一下,爬虫程序的三个步骤:

  1. 拼接正确的url(有中文或者特殊字符需要编码)
  2. 将获取到的东西保存

本节教程:http://c.biancheng.net/python_spider/crawl-webpage.html

根据教程写完,我们又发现了一些新的东西

py可以很容易的和用户交换信息,比如它不必写一个输入框或者文本域来让用户输入信息,py要获取用户输入的字符,只需写:

input("请输入内容:")

即可,这个函数会返回用户输入的值,咱可以拿一个变量去接受,即 userInput = input("请输入内容:")

py定义函数很特别,靠缩进来辨别函数体,没有大括号,所以py的函数长这样

def getUserInput(): # 用户输入 global userInput userInput = input("请输入内容:") return userInput

一旦缩进出现错误,那么此处也将不属于这个函数体,你可以自己试一下。

细心的你也许已经发现,上述函数中出现了关键字 global ,这是定义全局变量的方法,虽然定义在函数内部,但是其作用域是全局的,因为我们后续要对用户输入的中文字符进行转码,所以这里做一个全局变量来存储它,以便于最后给文件命名。

细心的你也许又发现,py定义函数的关键字是 def ,且因为没有大括号包裹函数体,它必须以return结束,否则程序无法知道这个函数是否结束,我是这么认为的。

本节教程写的代码,以及严先生整理的,函数式的修改,我都没看。

所以我写了如下,跟教程完全不同风格的代码,我自认为比较符合 js 思想

import uaListimport randomfrom urllib import requestfrom urllib import parse def getUserInput(): # 用户输入 global userInput userInput = input("请输入内容:") return userInput def buildHeader(): # 制作请求头 headers = { # 随机在序列中取元素,这个usList是我自定义的文件 'User-Agent': random.choice(uaList.ua_list) } return headers def makeUrl(url, param): # parse.urlencode 和 parse.quote的区别是 # 前者可以把对象(指js对象的形式,python好像叫集合)的键值对变成get请求的键值对,也就是 wd=爬虫 这种形式 return url.format(parse.urlencode(param)) def getHtmlDoc(url, param): req = request.Request( url=makeUrl(url, param), headers=buildHeader() ) # 创建请求 res = request.urlopen(req) # 发送请求 html = res.read().decode('utf-8') # 编码为utf-8,我不知道为什么 writeFiles(userInput, html) # 这里使用了全局变量 在定义是使用关键字 global (@line:9) return def writeFiles(fileNameIn, data): filename = parse.unquote(fileNameIn) + '.html' # 拼接文件名 with open(filename, 'w', encoding='utf-8') as f: # 写入文件,这里我也不懂,好像是py自带的东西 f.write(data) return getHtmlDoc("http://www.baidu.com/s?{}", { "wd": getUserInput()})

这次你可能没这么细心,我告诉你,倒数第三行在字符串中出现了一个大括号,这个大括号在字符串被读取时会被忽略(我认为),其作用是告诉 .format方法,后面拼接的东西该放在哪(我认为).format好像也是py自带的一个字符串处理方法。用法类似 c 语言中的 字符串变量格式化

printf("%s\n", str);

其中 %s 含义为 此处为字符串,对应后面的str。

参见:Python format 格式化函数C语言字符串的输入和输出

其实 ,这种写法在 c、js、python中都可以使用 参见 JavaScript console.log %c %o %s %d %f

至此,我们已经可以把一个页面完整的爬下来,上面的一小段程序会将 百度搜索结果页生成一个html文件,在项目根目录,恭喜各位。

本节教程:http://c.biancheng.net/python_spider/case01.html

严先生上来就教我们判断页面类型,笑话,我们用你教?

寻找URL变化规律,笑话,用你教?

编写爬虫程序,笑话...等等,这个跟前面的不太一样

出现了一个我听过,都不知道是什么的东西 class(类),看到这,相信很多大佬要指责我了,js也有类(es6),没错,但是我真没用过,刚刚 看了一下,这个东西还是个对象而已,要不怎么说js是个基于对象的语言呢?关于js的类,参见 终于,JavaScript也有了类(class)的概念

相信在座各位在公司都是一个被UI牵着鼻子,又被后端打着屁股的美丽小伙。我们只会切图和调接口啊,什么类啊,真不懂啊!

其实类没有什么复杂的,之所以不懂,是因为适用场景不多,因为没有很多的逻辑需要类来加持,有时使用一个对象就足够了,虽然类能很方便的管理变量和方法,但是我们一般还是习惯使用自定义对象来实现业务,对吧?

好的,既然你跟我想的一样,那么这节就基本结束了,因为基本逻辑和前面讲的是一样的,在本章代码的最后,出现了一个令人迷惑的东西,而严先生没有对此进行解释(知识诅咒)

if __name__=='__main__':

对此,请参见: Python中“if name=='main':”理解与总结 ,这个人讲的真好,建议给他点个赞。

最后的最后,严先生介绍了程序随机休眠的重要性

爬虫程序访问网站会非常快,这与正常人类的点击行为非常不符。因此,通过随机休眠可以使爬虫程序模仿成人类的样子点击网站,从而让网站不易察觉是爬虫访问网站,但这样做的代价就是影响程序的执行效率。

聚焦爬虫是一种执行效率较低的程序,提升其性能,是业界一直关注的问题,由此也诞生了效率较高的 Python 爬虫框架 Scrapy。

严先生写的 正则表达式基本语法 非常精炼易懂,作为前端程序员,我们用到正则表达式的机会还是很多的,所以相信大家多多少少都对正则表达式有一定的认识,在w3school或者菜鸟教程的教学乱的一批,建议换成严先生的教程。

菜鸟教程提供在线的正则测试 正则表达式在线测试

Python re模块用法详解 是对re模块(正则相关)的一些解读,大部分在讲正则表达式,可以略过,等用到时再搜

Python csv模块(读写文件) 介绍了csv文件的读写,可能很多同学对csv也比较熟悉,且在前端有过实践经验,这里主要介绍python的读写。

上面代码提到过写入文件,但是没有具体解释,因为那会我也不懂,就是这个 with open()

参见:https://blog.csdn.net/m0_48936146/article/details/124360734

应用以上所学的知识,我们就可以编写一个稍微复杂的爬虫,并在其中找出我们需要的数据了,我相信你会解决编写过程中遇到的问题!

接下来,我们略过课程:

[实例]抓取猫眼电影排行榜 主要讲正则的应用

Python Pymysql存储数据 主要描述在python中操作mysql数据库,如果你不会mysql,那你没必要学这章

[实例]抓取多级页面数据 主要讲正则应用的变体,和增量爬虫,增量爬虫就是只抓更新的部分

看到这三个标题,如果你不能快速的整理思路,那么你可以先查看一下这三节(我反正没看)

Requests 库

不知道你在做上面的例子的时候,有没有遇到过爬取页面要求你进行人机验证的,Requests 库有时可以有效地规避这个问题,同时,它是在python中应用最广泛的http请求库

方法 说明
requests.request() 构造一个请求对象,该方法是实现以下各个方法的基础。
requests.get() 获取HTML网页的主要方法,对应于 HTTP 的 GET 方法。
requests.head() 获取HTML网页头信息的方法,对应于 HTTP 的 HEAD 方法。
requests.post() 获取 HTML 网页提交 POST请求方法,对应于 HTTP 的 POST。
requests.put() 获取HTML网页提交PUT请求方法,对应于 HTTP 的 PUT。
requests.patch() 获取HTML网页提交局部修改请求,对应于 HTTP 的 PATCH。
requests.delete() 获取HTML页面提交删除请求,对应于 HTTP 的 DELETE。

由此可见,此库囊括了所有http请求方法,基于此,我们甚至可以写一个自己的接口测试工具

代理IP-proxies参数

一些网站为了限制爬虫从而设置了很多反爬策略,其中一项就是针对 IP 地址设置的。比如,访问网站超过规定次数导致流量异常,或者某个时间段内频繁地更换浏览器访问,存在上述行为的 IP 极有可能被网站封杀掉。可以使用浏览器插件:Proxy SwitchyOmega,可以便捷的更换ip代理

本节课程:Requests库常用方法及参数介绍

xpath的认识

接下来介绍一个你可能用过的东西 Xpath ,这个东西在前端也有应用,有一个js插件叫做 jsonpath,不知道你有没有听说过,简单说,jsonpath可以用特定的语法在复杂的json数据中查找

例如,我们现在有如下 json 数据

{ "objectTop":[ { name:"data1", id:1, status:"on" }, { name:"data2", id:2, status:"off" }, { name:"data3", id:3, status:"on" } ]}

我们要查找 status == on 的数据,按照正常思路,我们首先要遍历 objectTop ,大概这么写

function getStatusOn(){ let res = [] for(let item of objectTop){ if(item.status == "on") res.push(item) }}

或者使用 Object.x 去遍历,数组还可以使用filter或者map去遍历,当然这么写已经很方便了,但是jsonpath一行代码就可以搞定了,大概这么写

let res = jsonpath.query(objectTop,"$..[?(@.status == 'on')]")

更多关于 jsonpath 的教学 ,参见 JsonPath基本用法 npm上也有jsonpath的包可供下载。

解释一下上面表达式的大概含义

$:根节点 即 objectTop

.. : 递归查询(贪婪模式,查询到最后一级)

[?()] :里面包含条件语句

@. : 当前key(或者当前节点)

status == 'on' 是条件语句

这种写法好像一种 sql 语句,它其实大部分语法就遵循了Xpath

XPath(全称:XML Path Language)即 XML 路径语言,它是一门在 XML 文档中查找信息的语言,最初被用来搜寻 XML 文档,同时它也适用于搜索 HTML 文档。因此,在爬虫过程中可以使用 XPath 来提取相应的数据。

如果说 jsonpath 可以快速查找json节点,那么xpath就可以快速查找dom节点

有兴趣的还可以看一下xpath在前端的应用,参见: js用xpath定位获取元素

本节教程:Xpath简明教程(十分钟入门)

Xpath Helper是一款浏览器插件,可以便捷的自动生成查询语句

据我所知,咱们上边学了正则的方式查找元素,弄了半天有xpath这么个玩意,那上边的不白学了

浏览器实现抓包

这章我看了,我以为学个爬虫,还顺便教我们黑客技术,所谓的抓包,就是在浏览器的开发者工具看网络请求记录,看不起谁呢,我们是前端。下一章。

Python爬虫破解有道翻译

这章我看了,就是调了别人的接口,不用看。这章提到了一个术语,可能有的同学不知道:加盐,简单来说加盐就是加密,是一种很初级的加密手段。老王曾经这么跟我说的,加盐,就是加点佐料,吃着就不一样了。给一个明文加点佐料(盐),也就是加盐,这个明文就成了密文了。

Python爬虫抓取动态加载数据

这章我看了,还是调了别人的接口,不用看

Python json模块常用方法

import json,就完了

方法 说明
json.dumps() 将 Python 对象转换成 JSON 字符串。
json.loads() 将 JSON 字符串转换成 Python 对象。
json.dump() 将 Python 中的对象转化成 JSON 字符串储存到文件中。
json.load() 将文件中的 JSON 字符串转化成 Python 对象提取出来。

类似js中的 JSON.parse() 和 JSON.stringfy()

Python爬虫实现Cookie模拟登录

简单来说,有些网站登录后使用cookie保存登录状态,并且在向服务器请求时也携带cookie信息,相信大家或多或少也做过类似的业务,有时我们使用 Authorization 或者 携带 token 的方式(大多数时候)。cookie和ua一样,可以直接以字符串形式填写在header里,

headers = { "cookie": 'appmsglist_action_3228059900=card; RK=IC8o9cFlOq; ptcz=c4a3603f5d15ebc78f805034e793aaff8840473c18e1a6e595470b56b78ae125; ', "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.54" }

如果一个网站必须登录才能爬到有用的数据,那么你可以试一下这个方法,你会快速的收获成就感(我学到这已经帮公司写了一个公众号爬虫了)

Python多线程爬虫详解

线程这个概念对我们来说太复杂了,我不学了,不过跟着这章教程可以快速做出一个多线程爬虫

本节教程 Python多线程爬虫详解

Python BS4解析库用法详解

美味浓汤:Beautiful Soup 简称 BS4(其中 4 表示版本号)是一个 Python 第三方库

Beautiful Soup 将 HTML 文档转换成一个树形结构,比xpath好用一点点,各有千秋

bs4还提供了直接的css选择器和标签选择器,是真正比较直观的一个解析器

本节教程 Python BS4解析库用法详解

Python Selenium基本用法

Selenium 作为一款 Web 自动化测试框架,提供了诸多操作浏览器的方法。基本上可以实现任何 浏览器操作,模拟人手操作,例如:点击、输入、拖动、调整浏览器窗口大小(是的)、各种键盘事件。这章提到了“无界面浏览器”,也就是常说的(我不常说,不知道谁常说)无头浏览器

Python Scrapy爬虫框架详解

这章我看了,属于结丹期的功法,我也不会,就不讲了,灵根好的同学可以自行修炼。

至此,你已经达到了python爬虫筑基期修为,现在你可以 爬普通的网页和带登录验证的网页(对于凡人来说,你已经无所不能了)

总结:python好,真好,写出来第一个有用的爬虫程序时,幸福感滋儿一下就上来了(干净又卫生)。

学完这些,我们甚至还可以写接口测试了,后端甩给你一个图片AI识别的接口,让你把这 两千张图 测一下,我反手一个python脚本,跑了一个小时,完事。

老板问我能不能把公众号的文章同步到公司官网,没问题,一个小时写了个爬虫,十秒同步完成。

老板还是不满意,能不能每更新一次就自动同步到官网,没问题,这个叫定时增量爬虫,一个半小时足够了,部署到服务器,定时执行。

python真是太美好啦,我感觉我已经无所不能了。

俗话说的好:爬虫学的好,牢饭吃到饱。所以大家没事别老研究爬虫,影响自己的仕途。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK