手把手学爬虫第一弹——数据获取和解析

本文详细介绍了Python爬虫的基础知识,包括创建RequestsCookieJar对象设置Cookies、发起请求、会话请求、验证请求和处理超时异常。此外,还讲解了代理IP的使用,包括获取免费IP、验证IP可用性。接着,文章深入正则表达式,如行定位符、元字符、限定符等,并介绍了match()、search()、findall()等匹配方法。最后,探讨了BeautifulSoup库的简单应用和内容获取。
摘要由CSDN通过智能技术生成

headers = {

“User-Agent”: “Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36”

}

创建RequestsCookieJar对象,用于设置Cookies信息

cookies_jar = requests.cookies.RequestsCookieJar()

for cookie in cookies.split(‘;’):

key, value = cookie.split(‘=’, 1)

cookies_jar.set(key, value)

发起请求

response = requests.get(url, headers=headers, cookies=cookies_jar)

result = response.text

print(‘响应状态码:’, response.status_code)

print(‘请求内容为:’, result)

请添加图片描述


(3). 会话请求

前面我们利用Cookies实现了模拟登陆,但这样不仅操作麻烦,而且部分网页的Cookies会有时间限制,一段时间以后Cookies就会过期,为了解决这一问题我们可以使用requests提供的session对象。

import requests # 导入模块

s = requests.Session() # 创建一个会话对象

data = {‘username’: ‘mrsoft’, ‘password’: ‘mrsoft’}

response_1 = s.post(‘http://site2.rjkflm.com:666/index/index/chklogin.html’, data=data) # 发送登录请求

response_2 = s.get(‘http://site2.rjkflm.com:666’) # 获取登陆后的页面

print(‘登录信息:’, response_1.text)

print(‘登录后页面:’, response_2.text)

请添加图片描述


(4). 验证请求

我们在访问某些页面的时候会弹出验证,要求我们输入用户名和密码,这时就可以使用requests自带的验证功能,只需要在请求方法中填写auth参数,该参数的值是一个HTTPBasicAuth对象。

import requests # 导入模块

from requests.auth import HTTPBasicAuth # 导入HTTPBasicAuth类

url = ‘http://site2.rjkflm.com:666/spider/auth/’

auth = HTTPBasicAuth(‘admin’, ‘admin’)

response = requests.get(url=url, auth=auth)

print(response.text)

请添加图片描述


(5). 请求超时与异常捕获

我们在访问一个网页时可能会由于网络原因或者是服务器原因导致请求超时或者产生异常,这时候我们就可以为请求设置超时时间和异常捕获。

import requests # 导入模块

try:

url = ‘https://www.baidu.com’

response = requests.get(url=url, timeout=0.01) # 超时时间为0.01秒

print(‘响应状态码:’, response.status_code)

except Exception as e:

print(‘异常为:’, str(e))

请添加图片描述


4.代理服务


在爬取一些网页时我们肯那个会遇到一种情况,频繁访问后网页无法继续爬取了,这时候一般是我们的行为被服务器认定为恶意爬取,对我们的访问ip进行了屏蔽。针对于这种情况我们需要采用代理IP的形式访问。

(1). 在代码中写入多个ip

import requests # 导入网络请求模块

头部信息

headers = {‘User-Agent’: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ’

'AppleWebKit/537.36 (KHTML, like Gecko) ’

‘Chrome/72.0.3626.121 Safari/537.36’}

proxy = {‘http’: ‘http://117.88.176.38:3000’,

‘https’: ‘https://117.88.176.38:3000’} # 设置代理ip与对应的端口号

try:

对需要爬取的网页发送请求,verify=False不验证服务器的SSL证书

response = requests.get(‘http://2020.ip138.com’, headers=headers, proxies=proxy, verify=False, timeout=3)

print(response.status_code) # 打印响应状态码

except Exception as e:

print(‘错误异常信息为:’,e) # 打印异常信息

请添加图片描述


(2). 获取免费ip存储后使用

出现上面的情况多半是我们选择的ip为无效ip,针对这种情况我们一般会统一获取免费的代理ip,然后保存至文件,每次请求时都换一个新的IP.

a. 获取ip

import requests # 导入网络请求模块

from lxml import etree # 导入HTML解析模块

import pandas as pd # 导入pandas模块

import time

头部信息

headers = {‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36’}

ip_list = []

ip_table = pd.DataFrame(columns=[‘ip’]) # 创建临时表格数据

for i in range(1, 11):

print(“正在爬取第{}页”.format(i))

url = ‘http://www.ip3366.net/?stype=1&page={}’.format(i)

发送网络请求

response = requests.get(url=url, headers=headers)

response.encoding = ‘gb2312’ # 设置编码方式

if response.status_code == 200: # 判断请求是否成功

html = etree.HTML(response.text) # 解析HTML

ip = html.xpath(‘//*[@id=“list”]/table/tbody/tr/td[1]/text()’) # 获取ip内容

port = html.xpath(‘//*[@id=“list”]/table/tbody/tr/td[2]/text()’) # 获取端口号

for j in range(0, 10):

my_ip = ip[j] + ‘:’ + port[j]

print(‘代理ip为:’, ip[j], ‘对应端口为:’, port[j])

ip_list.append(my_ip)

time.sleep(1)

ip_table[‘ip’] = ip_list # 将提取的ip保存至excel文件中的ip列

生成xlsx文件

ip_table.to_excel(‘E:/python/pythonProject3/venv/Include/ip.xlsx’, sheet_name=‘data’)

b. 读取ip并判断是否可用

这种方式存在的问题就是免费网站获取的ip有国内的有国外的,有可用的有不可用的,所以存在ip是失效的问题,解决办法就是掏钱买专门的api接口。

import time

import requests # 导入网络请求模块

import pandas # 导入pandas模块

from lxml import etree # 导入HTML解析模块

ip_table = pandas.read_excel(‘E:/python/pythonProject3/venv/Include/ip.xlsx’) # 读取代理IP文件内容

ip = ip_table[‘ip’] # 获取代理ip列信息

头部信息

headers = {‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36’,

‘Accept-Language’: ‘zh-CN,zh;q=0.9’}

循环遍历代理IP并通过代理发送网络请求

for i in ip:

proxies = {‘http’: ‘http://{}’.format(i),

‘https’: ‘https://{}’.format(i)}

try:

verify=False不验证服务器的SSL证书

response = requests.get(‘http://2021.ip138.com/’, headers=headers, proxies=proxies, verify=False, timeout=10)

if response.status_code == 200: # 判断请求是否成功,请求成功说明代理IP可用

response.encoding = ‘utf-8’ # 进行编码

html = etree.HTML(response.text) # 解析HTML

info_1 = str(html.xpath(‘/html/body/p[1]/text()[1]’)).replace(“['\n”, “”).replace(“[']”, “”)

info_2 = str(html.xpath(‘/html/body/p[1]/a/text()’)).replace(“['”, “”).replace(“']”, “”)

info_3 = str(html.xpath(‘/html/body/p[1]/text()[2]’)).replace(“[‘] “, “”).replace(”\n’]”, “”)

print(info_1 + info_2 + info_3) # 输出当前ip匿名信息

time.sleep(3)

except Exception as e:

pass

print(‘错误异常信息为:’, e) # 打印异常信息

c.通过专门的API接口获取ip

import requests # 导入网络请求模块

from lxml import etree # 导入HTML解析模块

import time

url = ‘api接口’

headers = {‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36’}

response = requests.get(url=url, headers=headers)

ip = str(response.text).replace(“\r”, “”).replace(“\n”, “”)

proxies = {‘http’: ‘http://{}’.format(ip),

‘https’: ‘https://{}’.format(ip)}

print(proxies)

try:

verify=False不验证服务器的SSL证书

response = requests.get(‘http://2021.ip138.com/’, headers=headers, proxies=proxies, verify=False, timeout=10)

if response.status_code == 200: # 判断请求是否成功,请求成功说明代理IP可用

response.encoding = ‘utf-8’ # 进行编码

html = etree.HTML(response.text) # 解析HTML

info_1 = str(html.xpath(‘/html/body/p[1]/text()[1]’)).replace(“['\n”, “”).replace(“[']”, “”)

info_2 = str(html.xpath(‘/html/body/p[1]/a/text()’)).replace(“['”, “”).replace(“']”, “”)

info_3 = str(html.xpath(‘/html/body/p[1]/text()[2]’)).replace(“[‘] “, “”).replace(”\n’]”, “”)

print(info_1 + info_2 + info_3) # 输出当前ip匿名信息

time.sleep(3)

except Exception as e:

pass

print(‘错误异常信息为:’, e) # 打印异常信息

请添加图片描述


二、解析数据

==================================================================

当我们使用爬虫的时候大多数是为了爬取我们需要的部分数据,但直接获取到的往往不是我们需要的,这时候就需要我们对于爬取到的数据进行解析,进而在数据中找到我们需要的数据,接下来我将和大家一起使用正则(re)、Xpath、Beautiful Soup进行数据解析工作。

1. 正则表达式


正则表达式顾名思义就是由字符组成的表达式,这些表达式根据不同的组合可以匹配字符串中需要的部分。

(1). 正则表达式基础

a. 行定位符

行定位符用于描述字符串的边界。

| 符号 | 作用 |

| — | — |

| ^ | 表示行的开始 |

| $ | 表示行的结尾 |

b.元字符

元字符使用:

\bmr\w*\b

\b表示单词的边界

mr表示匹配开头是mr的字串

\e*表示匹配任意数量的字母或数字

该表达式可以匹配mrsoft、mrsbook、mr1234等字符串

| 代码 | 说明 |

| — | — |

| . | 匹配除换行符以外的任意字符 |

| \w | 匹配字母、数字、下划线、汉字 |

| \W | 匹配除了字母、数字、下划线、汉字以外的字符(与\w相反) |

| \s | 匹配任意空白符 |

| \S | 匹配除单个空白符(包括Tab和换行符)以外所有字符 |

| \d | 匹配数字 |

| \D | 匹配任意非数字 |

| \A | 从字符串开始处匹配 |

| \Z | 从字符串结束处匹配 |

| \b | 匹配一个单词的边界,单词分界符通常是空格、标点或者换行 |

| \B | 匹配非单词边界 |

| ^ | 匹配字符串的开始 |

| $ | 匹配字符串的结束 |

| () | 被括起来的表达式将作为分组 |

c. 限定符

上面提到"\w*"可以匹配任意数量的字母或数字。如果我们要匹配一定数量的数字,比如11位数的手机号?这时候就可以用限定符来实现。

^\d{11}$

匹配11位数的电话号码

| 符号 | 说明 | 举例 |

| — | — | — |

| ? | 匹配前面的字符零次或一次 | colour?r 可以匹配到colour和color |

| + | 匹配前面的字符一次或多次 | go+gle 可以匹配gogle到goooo…gle |

| * | 匹配前面的字符零次或多次 | go*gle 可以匹配ggle到goooo…gle |

| {n} | 匹配前面的字符串n次 | go{2}gle 只可以匹配google |

| {n,} | 匹配前面的字符最少n次 | go{2,}gle 可以匹配从google到goooo…gle |

| {n,m} | 匹配前面的字符最少n次,最多m次 | employe{0,2} 可以匹配employ、employe\employee |

d.字符类

假如我们要匹配所有大小写字母和数字,你会怎么做?列举所有的可能?显然不是,这时候我们可以使用正则表达式提供的字符类,将我们的条件放在中括号里面,例如:

[a-z0-9A-Z] # 可以匹配所有字母和数字

e. 排除字符

上面我们可以利用字符类获取我们想要的字符,那如何排除我们不需要的字符呢,很简单,在上面的表达式前面加一个^就可以了,例如:

[^a-zA-Z] # 可以匹配一个不是字母的字符

f. 选择字符

如果我们要在一堆字符里面找出所有的手机号码或者是身份证号码,如何运用正则表达式呢?分析一下身份证号码的组成,一共18位,前17位位数字,最后一位为数字或者是X,根据这一描述,我们显然可以得出如下的表达式:

[^\d{18}KaTeX parse error: Undefined control sequence: \d at position 4: |(^\̲d̲{17}(\d|X|x))

g. 转义字符

正则表达式的转义字符和python的转义字符基本没什么区别,例如当我们需要匹配的是个ip地址时,192.168.1.1中的.如何匹配呢?前面我们说到正则里面的点可以匹配一个任意字符,那这里就需要对其进行转义.

[1-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3} # 匹配ip地址

h. python中的正则表达式

在python里面我们一般不会写模式字符串,即在转义的地方加上\,这样会导致表达式中有大量的\,取而代之的是原生表达式,在表达式前面加上 R 或 r.

(2). match() 匹配

match()从字符串的开始位置匹配,如果在起始位置匹配成功就直接返回结果,反之返回None.

re.match(‘正则表达式’, ‘待匹配字符串’, ‘修饰符’)

例如:

re.match(‘mr_\w+’, ‘MR_SHOPmr_shop’, re.I)

I 表示不区分大小写

| 表达式 | 匹配效果 | 匹配结果 |

| — | — | — |

| re.match(‘mr_\w+’, ‘MR_SHOPmr_shop’, re.I) | 匹配以指定字符串开头 | <re.Match object; span=(0, 7), match=‘MR_SHOP’> |

| re,match(“.ello”, “hello”) | 匹配任意开头的字符串 | <re.Match object; span=(0, 5), match=‘hello’> |

(3). search() 匹配

search()方法不同于match()方法,search()会在整个字符串搜索第一匹配的值,匹配成功就返回,否则返回None。

re,search(“mr_\w+”, “MR_SHOP”, re.I)

re,search(“mr_\w+”, “项目名称 MR_SHOP”, re.I)

两个表示匹配结果一样

| 表达式 | 匹配效果 |

| — | — |

| \d? | 匹配多个数字,可有可无 |

| \b | 表示字符串的边界,可以是开头、结尾、空格以及换行 |

(4). findall()匹配

findall()方法会搜索整个字符串寻找符合要求的字符,并以列表的形式返回,如果没有匹配到就会返回空列表。

| 表达式 | 匹配效果 |

| — | — |

| re.findall(‘mr_\w+’, ‘MR_SHOP mr_shop’, re.I) | 所有指定字符开头的字符串 |

| re.findall(‘https://(.*)/’, ‘http://www.hao123.com/’) | 贪婪匹配,获取//开始到/前面的所有字符 |

| re.findall(‘https://(.*?)/’, ‘http://www.hao123.com/’) | 非贪婪匹配,这样可能匹配不到任何字符,因为匹配结果会尽可能少 |

(5). 字符串处理

  • 替换字符串

re.sub(‘正则表达式’, ‘要替换的字符串’, ‘要被替换的字符串’, ‘替换的最大次数,默认为0’, 修饰符)

import re

str = r’1[34578]\d{9}’

string = ‘中奖号码为3867363546 联系电话为:15071567345’

result = re.sub(str, ‘1**********’, string)

print(result)

输出结果为: 中奖号码为3867363546 联系电话为:1**********

  • 分割字符串

re.split(‘正则表达式’, ‘要匹配的字符串’, 最大拆分次数, 修饰符)

import re

str = r’[?|&]’

url = ‘http://www.baidu.com?a=12&b=3’

result = re.split(str, url)

print(result)

输出结果为: [‘http://www.baidu.com’, ‘a=12’, ‘b=3’]

2. Xpath解析


上一节我们学了正则表达式清洗数据,这一节我们学习一种更加便捷的数据清洗解析方式,XPath。这是一种基于XML的路径语言。

Xpath常用的路径表示:

| 表达式 | 描述 |

| — | — |

| nodename | 此节点的所有子节点 |

| / | 从当前节点选取子节点 |

| // | 从当前节点选取子孙节点 |

| . | 选取当前节点 |

| … | 选取当前节点的父节点 |

| @ | 选取属性class |

| * | 选取所有节点 |

这种解析方式主要熟悉网页结构,利用上面的路径表达式选取对应的路径。浏览器也提供了直接复制的Xpath路径,使用如下:

请添加图片描述

这里我就不再详细介绍这种解析方法,大家可以参考这位博主的文章,写的很详细了!Xpath解析数据

请添加图片描述

from lxml import etree

import requests

url = “https://wuhan.zbj.com/search/f/?type=new&kw=%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%BC%80%E5%8F%91”

resp = requests.get(url)

xml = resp.text

tree = etree.HTML(xml)

res = tree.xpath(‘//div[@class=“service-info-wrap”]’)

print(res)

for item in res:

price = item.xpath(‘./div[@class=“service-price clearfix”]/span/text()’)

title = item.xpath(‘./div[@class=“service-title”]/p/text()’)

result = {

“price”: ‘’.join(price),

“title”: ‘’.join(title)

}

print(result)

请添加图片描述


3. BeautifulSoup解析


BeautifulSoup是一个用于从HTML和XML中提取数据的Python库。

(1). BeautifulSoup的简单应用

使用第一步先导入bs4库,然后创建一个BeautifulSoup对象指定选用的解析器。

from bs4 import BeautifulSoup # 导入BeautifulSoup库

创建模拟HTML代码的字符串

html_doc = “”"

第一个 HTML 页面

body 元素的内容会显示在浏览器中。

title 元素的内容会显示在浏览器的标题栏中。

“”"

创建一个BeautifulSoup对象,获取页面正文

soup = BeautifulSoup(html_doc, features=“lxml”)

print(soup) # 打印解析的HTML代码

print(type(soup)) # 打印数据类型

这样我们就完成了数据的第一步处理工作

(2). 获取节点内容

下面以一个例子加代码注释解释如何获取节点内容。

  • 获取节点源代码

from bs4 import BeautifulSoup # 导入BeautifulSoup库

创建模拟HTML代码的字符串

html_doc = “”"

第一个 HTML 页面

body 元素的内容会显示在浏览器中。

title 元素的内容会显示在浏览器的标题栏中。

“”"

创建一个BeautifulSoup对象,获取页面正文

soup = BeautifulSoup(html_doc, features=“lxml”)

“”"

获取节点内容

“”"

print(‘head节点内容为:\n’, soup.head) # 打印head节点

请添加图片描述

  • 获取节点属性

在已选择的节点后面加上.attrs即可

创建模拟HTML代码的字符串

html_doc = “”"

横排响应式登录

“”"

创建一个BeautifulSoup对象,获取页面正文

soup = BeautifulSoup(html_doc, features=“lxml”)

print(‘meta节点中属性如下:\n’,soup.meta.attrs)

print(‘link节点中属性如下:\n’,soup.link.attrs)

请添加图片描述

  • 获取节点的文本内容

在已获取的节点后面加上.string即可。

from bs4 import BeautifulSoup # 导入BeautifulSoup库

创建模拟HTML代码的字符串

html_doc = “”"

横排响应式登录

“”"

创建一个BeautifulSoup对象,获取页面正文

soup = BeautifulSoup(html_doc, features=“lxml”)

print(‘titlt节点中的文本如为:’, soup.title.string)

请添加图片描述

(3). 方法获取内容

  • find_all()方法——获取所有符合条件的节点

find_all(name=None, attrs={}, recursive=True, text=None, limit=None, **kwaigs)

最后

Python崛起并且风靡,因为优点多、应用领域广、被大牛们认可。学习 Python 门槛很低,但它的晋级路线很多,通过它你能进入机器学习、数据挖掘、大数据,CS等更加高级的领域。Python可以做网络应用,可以做科学计算,数据分析,可以做网络爬虫,可以做机器学习、自然语言处理、可以写游戏、可以做桌面应用…Python可以做的很多,你需要学好基础,再选择明确的方向。这里给大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!

👉Python所有方向的学习路线👈

Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。

👉Python必备开发工具👈

工欲善其事必先利其器。学习Python常用的开发软件都在这里了,给大家节省了很多时间。

👉Python全套学习视频👈

我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。

👉实战案例👈

学python就与学数学一样,是不能只看书不做题的,直接看步骤和答案会让人误以为自己全都掌握了,但是碰到生题的时候还是会一筹莫展。

因此在学习python的过程中一定要记得多动手写代码,教程只需要看一两遍即可。

👉大厂面试真题👈

我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

需要这份系统化学习资料的朋友,可以戳这里无偿获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值