手刃一个善意的小爬虫(一),使用re模块进行爬虫

爬虫是什么?

爬虫技术也称为网络爬虫、网络蜘蛛或网络机器人,是一种自动化获取互联网信息的程序或脚本。

爬虫技术通过程序自动访问网络资源,并将有用的数据抓取下来,存储到本地或远程服务器中。爬虫技术可以自动获取大量的数据,极大地提高了数据获取的效率和准确性,同时也为人们提供了更多的数据分析和挖掘的可能性。爬虫主要针对于网络网页,可以自动化浏览网络中的信息,或者说是一种网络机器人。它们被广泛用于互联网搜索引擎或其他类似网站,以获取或更新这些网站的内容和检索方式(概念来源于百度)

爬虫合法吗?

爬虫技术本身在法律上并不被禁止,但是利用爬虫技术获取数据的行为具有违法甚至犯罪的风险。

爬虫技术的合法性取决于其使用方式和应用范围。如果爬虫程序遵守网站设置的反爬虫措施,不侵犯他人知识产权、个人信息等,并且用于合法目的,如数据分析、市场研究等,通常不会构成违法行为。然而,如果爬虫技术用于非法获取或侵犯他人隐私、商业秘密等,或者干扰被访问网站的运营,甚至用于制作和传播计算机病毒等破坏性程序,这些行为就可能构成犯罪。

此外,爬虫技术在获取数据时,应遵守相关网站的robots协议,尊重网站的版权声明和隐私政策。总的来说,爬虫技术的使用必须在遵守法律规定和道德规范的前提下进行。

善意的爬虫:不破坏被爬取的网站的资源(正常访问,一般频率不高,不窃取用户隐私)

恶意的爬虫:影响网站的正常运营(抢票、秒杀、疯狂solo网站资源造成网站宕机)

爬虫的矛与盾

反爬机制:门户网站可以通过制定相应的策略或者技术手段,防止爬虫程序进行网站数据的爬取。

反反爬策略:爬虫程序可以通过制定相关的策略或者技术手段,破解门户网站中具备的反爬机制,从而可以获取门户网站中相关的数据。

robots.txt协议:君子协议,规定了网站中哪些数据可以被爬虫爬取哪些数据不可以被爬取。

第一个爬虫小程序

需求:用程序模拟浏览器,输入一个网址,从该网址中获取到资源或者内容

python 复制代码
from urllib.request import urlopen

url = "http://www.baidu.com"
resp = urlopen(url)

# 将读取到的内容保存到mybaidu.html文件中
with open("mybaidu.html", mode="w", encoding="utf-8")as f:
   f.write(resp.read().decode("utf-8"))  # 读取到网页的页面源代码
print("over!")

保存到文件的内容如下,读取到的是网页的源代码。

这样我们就成功的从百度上爬取到了一个网页的源代码,是不是超级简单呢?

使用requests进行爬虫

安装requests包:pip install requests

需求:在搜狗引擎中搜索周杰伦,拿到页面中的数据,页面搜索如下图:

按照如下代码运行:

这里只是非常简单的使用了一个get请求作为一个小演示

ini 复制代码
import requests

url = "https://www.sogou.com/web?query=周杰伦"
resp = requests.get(url=url)
print(resp)
print(resp.text)  # 拿到页面源代码
resp.close()  #关闭请求

运行结果如下:

我们可以看到,运行结果出现了一点问题,并没有正确拿到页面中的源代码。这是什么原因呢?因为服务器检测到此次请求不是在正常浏览器中发送的,而是通过爬虫程序请求的。

要如何伪装的更像是浏览器正常发送的呢?

我们在浏览器中打开检查,找到第一个请求,在Requests Headers(请求头)中找到User-Agent,这个参数是描述当前的请求是通过哪个设备发送的,将这个参数添加到程序中。

改动之后的代码如下:

ini 复制代码
import requests

url = "https://www.sogou.com/web?query=周杰伦"

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
}
resp = requests.get(url=url, headers=headers)
print(resp)
print(resp.text)  # 拿到页面源代码
resp.close()  #关闭请求

运行之后发现结果正常,可以拿到页面上的源代码,这其实就是我们处理了一个小小的反爬

数据解析

上面我们基本掌握了抓取整个网页的基本技能,但是大多数情况下我们并不需要整个网页的全部内容,只是需要那么一小部分,这就涉及到了数据提取的问题。

1、正则表达式

Regular Expressiom,正则表达式,一种使用表达式的方式对字符串进行匹配的语法规则。

我们抓取到的网页源代码本质上就是一个超长的字符串,想从里面提取内容,用正则再合适不过了。

正则的优点:速度快,效率高,准确性高。

正则的缺点:新手上手难度有点儿高。

正则的语法: 使用元字符(具有固定含义的特殊符号)进行排列组合用来匹配字符串

常用元字符:

量词: 控制前面的元字符出现的次数

贪婪匹配和惰性匹配

这两个要着重的说一下,因为我们写爬虫用的最多的就是这个惰性匹配

案例:

str:玩儿吃鸡游戏,晚上一起上游戏,干什么呢?打游戏啊!

(1)reg:玩儿.*?游戏

此时的匹配结果:玩儿吃鸡游戏

(2)reg:玩儿.*游戏

此时的匹配结果:玩儿吃鸡游戏玩儿吃鸡游戏,晚上一起上游戏,干什么呢?打游戏啊!

2、re模块

(1)findall: 匹配字符串中所有的符合正则的内容,返回的是一个列表

python 复制代码
import re

# findall: 匹配字符串中所有的符合正则的内容,返回的是一个列表
lst = re.findall(r"\d+", "我的电话号码是:10086,我女朋友的电话号码是:10010")
print(lst)

运行结果:

(2)finditer: 匹配字符串中所有的符合正则的内容,返回的是一个迭代器,从迭代器中拿到内容需要.group()

python 复制代码
# finditer: 匹配字符串中所有的符合正则的内容,返回的是一个迭代器,从迭代器中拿到内容需要.group()
it = re.finditer(r"\d+", "我的电话号码是:10086,我女朋友的电话号码是:10010")
for i in it:
    print(i.group())

运行结果:

注意:迭代器的效率要比列表高的多。

(3)search:找到一个结果就返回,返回的结果是match对象,拿数据需要.group

python 复制代码
# search,找到一个结果就返回,返回的结果是match对象,拿数据需要.group
s = re.search(r"\d+", "我的电话号码是:10086,我女朋友的电话号码是:10010")
print(s.group())

运行结果:

(4) match:从头开始匹配

python 复制代码
# match:从头开始匹配
m = re.match(r"\d+", "我的电话号码是:10086,我女朋友的电话号码是:10010")
print(m.group())

运行结果:匹配到的内容是空的

代码修改之后:

python 复制代码
# match:从头开始匹配
m = re.match(r"\d+", "10086,我女朋友的电话号码是:10010")
print(m.group())

运行结果:

以上是爬虫过程中常用的方法,使用最多的是finditer

补充说明:

(1)预加载正则表达式,也就是提前写入一段正则表达式,在需要用到的时候直接拿来使用。

使用方法如下:

python 复制代码
# 预加载正则表达式
obj = re.compile(r"\d+")
ret = obj.finditer("我的电话号码是:10086,我女朋友的电话号码是:10010")
for i in ret:
    print(i.group())

(2)提取正则匹配结果中的一段固定的内容

例如:想匹配如下html内容中,全部的姓名

xml 复制代码
s = '''
<div class='张三'><span id='1'>喜欢吃饭</span></div>
<div class='李四'><span id='2'>喜欢玩游戏</span></div>
<div class='王五'><span id='3'>喜欢踢足球</span></div>
<div class='赵四'><span id='4'>喜欢唱歌</span></div>
<div class='王麻子'><span id='5'>喜欢谈恋爱</span></div>
'''

代码如下:

xml 复制代码
s = '''
<div class='张三'><span id='1'>喜欢吃饭</span></div>
<div class='李四'><span id='2'>喜欢玩游戏</span></div>
<div class='王五'><span id='3'>喜欢踢足球</span></div>
<div class='赵四'><span id='4'>喜欢唱歌</span></div>
<div class='王麻子'><span id='5'>喜欢谈恋爱</span></div>
'''
# 匹配以上字符串内容中,全部的姓名
# (?P<分组名字>正则表达式)可以单独从正则匹配的内容中进一步提取内容
obj = re.compile(r"<div class='(?P<name>.*?)'><span id='\d+'>.*?</span></div>", re.S)  # re.S:让.能匹配换行符
result = obj.finditer(s)
for it in result:
    print(it.group("name"))

运行结果:

小小实战一下

(1)案例1:爬虫豆瓣电影 Top 250,希望取到的内容为:电影名称、年份、评分、评价人数,并将数据保存成csv格式

页面源代码:

爬虫代码如下:

python 复制代码
import requests
import re
import csv

url = "https://movie.douban.com/top250"
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
}
resp = requests.get(url=url, headers=headers)
page_content = resp.text
# 解析数据
obj = re.compile(r'<li>.*?<div class="item">.*?<span class="title">(?P<name>.*?)'
                 r'</span>.*? <p class="">.*?<br>(?P<year>.*?)&nbsp'
                 r'.*?<span class="rating_num" property="v:average">(?P<score>.*?)</span>'
                 r'.*?<span>(?P<num>.*?)人评价', re.S)
result = obj.finditer(page_content)
f = open("data.csv", mode="w",encoding="utf-8")
csvwrite = csv.writer(f)
for it in result:
    # # 将数据打印到控制台
    # print(it.group("name"))
    # # .strip()去掉年份前面的一大片空白
    # print(it.group("year").strip())
    # print(it.group("score"))
    # print(it.group("num"))

    # 将数据整理成字典的格式
    dic = it.groupdict()
    # 年份前面有空格,特殊处理
    dic['year'] = dic['year'].strip()
    csvwrite.writerow(dic.values())

f.close()
print("OVER!")

运行之后,查看csv文件中的内容:

(2)案例2:进入盗版电影天堂网站 www.dytt89.com/ 中,爬取2024必看热片中电影的名称和下载地址

首页的页面源代码:

子页面的页面源代码:

步骤:

(1)打开网站,定位到2024必看热片;

(2)从2024必看热片中提取到子页面的链接地址;

(3)请求子页面的链接地址,拿到我们想要的下载地址。

代码实现如下:

python 复制代码
import requests
import re

domain = "https://www.dytt89.com/"
resp = requests.get(domain, verify=False)  # verify=False 去掉安全验证
# 指定字符集,因为这个网站的编码格式为:charset=gb2312",如果不指定字符集,则拿到的网页源代码会乱码
resp.encoding = "gb2312"
# print(resp.text)

# 提取数据,拿到2024必看热片中ul里面的li
obj1 = re.compile(r"2024必看热片.*?<ul>(?P<li>.*?) </ul>", re.S)
# 提取每个li中的href
obj2 = re.compile(r"<a href='(?P<href>.*?)' title", re.S)
# 提取子页面电影的下载链接
obj3 = re.compile(
    r'◎片  名(?P<movie>.*?)<br />.*?<td style="WORD-WRAP: break-word" bgcolor="#fdfddf"><a href="(?P<download>.*?)">',
    re.S)

child_href_list = []
result1 = obj1.finditer(resp.text)
for it1 in result1:
    li = it1.group("li")
    # 提取子页面的链接
    result2 = obj2.finditer(li)
    for it2 in result2:
        href = it2.group("href")  # 这里取到的href是:/i/109813.html
        # 拼接子页面的url地址:域名+子页面地址
        child_href = domain + href.strip("/")
        # 把子页面的链接保存到集合中
        child_href_list.append(child_href)

# 提取子页面的内容,与上述大部分是重复的

for href in child_href_list:
    child_resp = requests.get(url=href, verify=False)
    child_resp.encoding = "gb2312"
    # 这里用search是因为本来就只能匹配一个结果,如果用finditer还需要再写个循环,上面的finditer也可以改成search,匹配当前正则的都是只有一个结果
    result3 = obj3.search(child_resp.text)
    print(result3.group("movie"))
    print(result3.group("download"))
    # break # 加上break是为了循环只跑一次

print("OVER!")

运行结果:

我们可以看到电影名称和下载链接都取到了,自己也可以根据上面已讲述的方法,将数据写到文件中。到这里使用re模块的爬虫就结束了,是不是很有成就感呢?

看完了吧,请发表你的评论,我也不介意你点个赞,嘻嘻嘻~

相关推荐
帅得不敢出门3 天前
安卓使用memtester进行内存压力测试
android·压力测试·测试·硬件测试
每周都想吃火锅9 天前
如何在postman中传入文件参数
postman·测试
HinsCoder10 天前
【测试】——Selenium API (万字详解)
自动化测试·笔记·学习·selenium·测试工具·web·测试
大柏怎么被偷了12 天前
【测试】什么是需求?
测试
郝同学的测开笔记14 天前
PyQt6 中的布局管理
后端·python·测试
南风与鱼15 天前
软件测试 BUG 篇
bug·测试
四格15 天前
如何使用 Bittly 进行基于串口的自动化测试
嵌入式·测试
Lossya17 天前
【自动化测试】常见的自动化遍历工具以及如何选择合适的自动化遍历工具
自动化测试·功能测试·测试工具·自动化·测试
HinsCoder17 天前
【渗透测试】——Upload靶场实战(1-5关)
笔记·学习·安全·web安全·渗透测试·测试·upload靶场
大柏怎么被偷了18 天前
【软件测试】测试的岗位有哪些?
软件测试·测试