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

时间:2022-12-23 16:09:48

我踏马来辣

还有一件事:

  1. 本教程配合c语言中文网 python爬虫 教程 食用
  2. 本教程不适用于未成年人
  3. 一定要刷牙
  4. 本教程不存在知识诅咒
  5. 学完本教程即可进入筑基期
  6. js 基础和本教程学习效率成正比
  7. 不要笑
  8. 暂时不要驾驶你的行李箱
  9. 本教程是针对前端程序员制定的
  10. 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.request
response = 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)
}

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

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

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

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

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

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

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

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

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

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

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

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

在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%AB
result = parse.unquote(url)
print(result)
#爬虫

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

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

开始辣

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

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

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

本节教程: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 uaList
import random
from urllib import request
from 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真是太美好啦,我感觉我已经无所不能了。

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