Python爬虫(第一周)

目录

一、正则表达式

正则表达式的作用

正则表达式的使用

1.match函数

匹配单个字符(规范字符类型)

匹配多个字符(规范字符数量)

匹配开头和结尾

2.search函数

小案例

3.findall函数

4.贪婪与非贪婪

二、爬虫

爬虫的概念

网络通信

爬虫的分类

爬虫的基本流程


一、正则表达式

正则表达式的作用

爬虫:数据的提取       

           例如:从 xxxxxxxxx.www.baidu.comxxxxxxx中将www.baidu.com提取出来

前后端:数据的规范

           例如:检验用户输入的手机号是不是十一位数字

正则表达式:不是独属于Python的,是跨语言的。

正则表达式的使用

# 导入re模块    (他只是一个python文件:re.py)
import re

导入re模块后,当我们输入 re. 后Pycharm会自动提示有哪些可用的函数和方法

下面我们介绍一些在爬虫中常用的函数和方法

1.match函数

def match(pattern, string, flags=0):
    """Try to apply the pattern at the start of the string, returning
    a Match object, or None if no match was found."""
    return _compile(pattern, flags).match(string)

我们从re.py中查看match函数,可以看到match函数有两个必须传值的形参(pattern,string)和一个默认参数(flags)

pattern:传入正则表达式(提取规则,即提取内容需要满足的条件)

string:传入字符串(从该字符串中提取内容)

其次,match函数有返回值,所以我们在调用时需要一个变量进行返回值的接收

import re


# 目的:判断s字符串是不是以hello开头
s = 'hello,python'
res_ = re.match(r'hello', s)
print(res_)    # 返回值: <re.Match object; span=(0, 5), match='hello'>

match的返回值是一个对象,只要目标字符串出现,match函数就是匹配成功的

匹配不成功返回值是:None

匹配单个字符(规范字符类型)

需求:豆瓣电影中有很多的电影,但我们只想要匹配哈利波特1-7部的,那我们应该怎么做呢?

# 匹配七次
import re


re.match(r'哈利波特1','哈利波特1')
re.match(r'哈利波特2','哈利波特2')
re.match(r'哈利波特3','哈利波特3')
re.match(r'哈利波特4','哈利波特4')
re.match(r'哈利波特5','哈利波特5')
re.match(r'哈利波特6','哈利波特6')
re.match(r'哈利波特7','哈利波特7')

以上代码缺点很明显,七部电影需要匹配七次,非常麻烦,那我们有什么通用一点的办法吗?

所以我们引入单个字符的匹配

# 通用办法
import re


res_ = re.match(r'哈利波特\d','哈利波特6')    # \d可以代表一位数字
print(res_)

在这种情况下,第二个参数无论是哈利波特1,还是哈利波特2,还是哈利波特3......都可以匹配成功,可是这会出现另一个问题,我们到底匹配成功的是哪一部呢?是1还是2,3,4?所以匹配到的数据我们可以通过group()方法接收

data = res_.group()
print(data)

问题:当网站数据出现问题,比如多出来部哈利波特8,而实际上没有这部电影,我们通过上面的办法也会将哈利波特8匹配成功,所以当需求不一样时,我们的匹配规则也需要变化

import re


res_ = re.match(r'哈利波特[1234567]', '哈利波特8')    # []:表示匹配[]中列举的一个字符
# res_ = re.match(r'哈利波特[1-7]', '哈利波特8')    # 简单写法
print(res_)    # 匹配不成功

[ ]中的内容在一些情况下有简单写法:1. 数字:0-9

                                                             2. 小写字母:a-z

                                                             3. 大写字母:A-Z

在这里,我们给出单个字符匹配的规则表

.匹配任意1个字符(除了\n之外)
[ ]匹配[ ]中列举的字符
\d匹配单个数字:0,1,2,3,4,5,6,7,8,9
\D匹配非数字
\s匹配空白,即空格和Tab(缩进)
\S匹配非空白
\w匹配单词字符,即a-z,A-Z,0-9,_
\W匹配非单词字符

\w 不推荐使用,匹配内容非官网文档所介绍的:a-z,A-Z,0-9,_

import re


res_ = re.match(r'哈利波特\w', '哈利波特一')
print(res_)

按照官方文档中介绍的规则,是应该匹配失败的,但是实际上是匹配成功的

匹配多个字符(规范字符数量)

问题:如果哈利波特拍的太好了,出到了第11部,那我们该如何匹配呢?

import re


res_ = re.match(r'哈利波特\d','哈利波特11')    # \d可以代表一位数字
print(res_)

如果使用匹配单个字符的方法,上述代码匹配到的结果是:哈利波特1

所以要想实现我们的目的,需要引入匹配多个字符,下面是一些常用的匹配规则:

*匹配前一个字符出现0次或者无限次,即可有可无
+匹配前一个字符出啊先1次或者无限次,即至少有1次
匹配前一个字符出现1次或者0次,即要么有1次要么没有
{m}匹配前一个字符出现m次
{m,n}匹配前一个字符出现m到n次

重点:匹配前一个字符,即依赖前一个字符

import re

# 解决电影名称的问题
res_ = re.match(r'哈利波特\d{1,2}','哈利波特11')    # \d可以代表一位数字,{1,2}表示1到2位
print(res_)


# 匹配电话号
res_1 = re.match(r'\d{11}', '15193039859')    # 匹配11位数字
print(res_1)
phone_ = res_1.group()
print(phone_)


# 匹配qq号
res_2 = re.match(r'\d{6,12}', '925290303')    # 匹配6-12位数字
print(res_2)
qq_number = res_2.group()
print(qq_number)

匹配开头和结尾

^匹配字符串开头
$匹配字符串结尾

2.search函数

import re


# match和search的区别
# 匹配中间的数字
s = 'abc123456def'

res_1 = re.match(r'\d{6}', s)
print(res_1)    # None

res_2 = re.search(r'\d{6}', s)
print(res_2)    # <re.Match object; span=(3, 9), match='123456'>

match函数默认匹配开头

search函数从开头开始搜索,匹配到符合规范的返回结果

小案例

匹配QQ邮箱:qq号+@qq.com

分析:1. 6-12位的qq号

           2. @后面的qq可以大写可以小写

           3. 以com结尾

import re


email_ = input('请输入QQ邮箱:')

res_ = re.match(r'\d{6,12}@[Qq]{2}.com', email)
print(res_)

上述代码看似正确,但是存在一些小bug:输入925290303@qq#com时匹配成功

                                                                    输入925290303@qq.comm时匹配成功

分析:1. 在正则表达式中,“ . ”表示匹配任意一个字符(\n)除外,所以会出现第一种匹配成功

           2. match默认匹配开头,当满足“ \d{6,12}@[Qq]{2}.com ” 时无论后面再出现什么字符都会匹配成功

解决:1. [ ] , . , * , ? 只是当普通字符出现,而不是作为正则表达式的规则出现时,我们需要对其进行转义操作:在这些字符前面加上 \ 即可

           2. 在match匹配时规定匹配结尾

import re


email_ = input('请输入QQ邮箱:')

res_ = re.match(r'\d{6,12}@[Qq]{2}\.com$', email)
print(res_)

分组

import re


email_ = input('请输入QQ邮箱:')

res_ = re.match(r'\d{6,12}@(qq|QQ)\.com$', email)    # qq,QQ其中任意一个都行
print(res_)

()可以进行分组,括号里的是单独的逻辑作用不到外面

3.findall函数

引入:我们得到的3个人的qq号信息:小明:123456789,小王:23456789,小李:3215647 我们需要将三个人的qq号都提取出来,此时search和match都不能满足我们的需求,就需要使用一个新的函数:findall来实现

import re


info_ = '小明:123456789,小王:23456789,小李:3215647'

res_1 = re.search(r'\d+', info_)
print(res_1)
print(res_1.group())    # 123456789

res_2 = re.findall(r'\d+', info_)
print(res_2)    # ['123456789', '23456789', '3215647']

从中我们可以发现区别:

search函数匹配到一个符合规范的就返回结果,不继续搜索,返回值为对象

findall函数匹配所有符合规范的结果,返回值为由符合规范结果构成的列表,没有匹配到返回一个空列表

无论需要匹配几个一般都采用findall函数,search函数在没有匹配到符合规则的内容时调用group方法会报错(影响程序运行),findall没有匹配到符合规则的内容时返回空列表

我们可以使用findall函数和()分组获取长字符串中符合规则的内容

import re


s = '<link data-vue-meta="true" rel="canonical" href="https://www.bilibili.com/video/BV1Zs41137Tr/">'

# 从标签中提取视频链接
url_ = re.findall(r'<link data-vue-meta="true" rel="canonical" href="(.*)">', s)
print(url_)

4.贪婪与非贪婪

贪婪:正则表达式默认是贪婪的,取得越多越好

非贪婪:加上一个 ?,只匹配第一个满足的

import re


s = '<link data-vue-meta="true" rel="canonical" href="https://www.bilibili.com/video/BV1Zs41137Tr/">'

# 从标签中提取视频链接(非贪婪)
url_ = re.findall(r'<link data-vue-meta="true" rel="canonical" href="(.*?)">', s)
print(url_)

二、爬虫

爬虫的概念

爬虫就是模拟客户端发送网络请求,接受请求对应的响应,按照一定的规则自动抓取互联网信息的程序。

客户端(浏览器),一般情况下操作者是正常用户,当我们用爬虫模拟客户端时,服务器时不欢迎我们的,所以我们应该尽可能的去模拟正常用户去发送请求。

爬虫:模拟客户端访问,抓取数据 ---> 我们做的事情

反爬:保护重要数据,阻止恶意网络攻击 ---> 网站的后端服务器,识别爬虫

反反爬:针对反爬措施 ---> 我们做的事情,尽量模拟正常用户:1.属性(静态)

                                                                                                     2.行为(动态)

网络通信

1.电脑(浏览器)输入url:www.baidu.com(域名)

2.DNS服务器:IP地址标注的服务器 由www.baidu.com找到对应的IP地址1.1.1.1,DNS服务器将IP地址返回给浏览器

3.浏览器拿到IP地址去访问服务器,返回响应

一个请求(www.baidu.com)只能对应一个数据包(文件),就好比www.baidu.com这个请求,实际上只能获取到一个数据包:html数据,他是不包含图片、css、js的,但是我们在www.baidu.com的Networks里面看到了n个数据包,这些数据包共同组成了这个页面(n个数据包 -> n个请求 - > n个不同的url)。而产生这种现象都是浏览器的功劳:浏览器会帮助我们把url(www.baidu.com -> https://www.baidu.com/)补全,得到这个数据包(www.baidu.com)的响应,浏览器发现,这个数据包(www.baidu.com)的响应里面缺少了很多东西,对于这些缺少的部分浏览器会自动帮我们发送请求,获取响应,渲染完整,最终组成完整的页面。

爬虫的分类

通用爬虫通常值搜索引擎和大型Web服务提供商的爬虫

聚焦爬虫

(针对特定网站的爬虫,定向的获取某方面数据的爬虫)

累计式爬虫从开始到结束,不断进行爬取,过程中进行去重操作
增量式爬虫已下载网页采取增量式更新和只爬取新产生的或者已经发生变化网页的爬虫
Deep Web爬虫不断通过静态链接获取的,隐藏在搜索表单后的,只有用户提交一些关键词才能获得的web页面

爬虫的基本流程

1.确认目标:确认目标的url:www.baidu.com

2.发送请求:发送网络请求,获取特定的服务端给你的响应

3.提取数据:从响应中提取到特定的数据,jsonpath,xpath为主,re为辅

4.保存:本地(html,json,txt)或者数据库

获取到的响应当中,有可能提取到了还需要发送请求的url,我们就拿着解析到的url继续发送请求

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不懂编程的大学生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值