爬虫

爬虫


简单概念

网络爬虫:模拟浏览器发送网络请求,接受请求响应,一种按一定规则,自动地抓取互联网信息的程序

  • 可以用于自动地从网络上获取信息,节省人工

Preparation

  • 可以使用python
  • 一些可能使用到的库:
    1
    2
    3
    4
    5
    6
    7
    # -*- codeing = utf-8 -*-
    from bs4 import BeautifulSoup # 网页解析,获取数据
    import re # 正则表达式,进行文字匹配`
    import urllib.request, urllib.error # 制定URL,获取网页数据
    import xlwt # 进行excel操作
    #import sqlite3 # 进行SQLite数据库操作

  • # coding=utf-8# -*- coding: utf-8 -*- 来指定源代码的编码方式,防止乱码

大体流程

  1. 爬取网页
  2. 逐一解析数据
  3. 保存网页

详细展开

爬取网页:

1
2
for i in range(0, 10):  # 调用获取页面信息的函数,10次
url = baseurl + str(i * 25)

baseurl是要爬虫的网址,加上的str(i*25)是用于 翻页 ,通过这样子设置可以跳转到不同的界面

askURL()用于请求网页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def askURL(url):
head = { # 模拟浏览器头部信息,向豆瓣服务器发送消息
"User-Agent": "Mozilla / 5.0(Windows NT 10.0; Win64; x64) AppleWebKit / 537.36(KHTML, like Gecko) Chrome / 80.0.3987.122 Safari / 537.36"
}
# 用户代理,表示告诉豆瓣服务器,我们是什么类型的机器、浏览器(本质上是告诉浏览器,我们可以接收什么水平的文件内容)

request = urllib.request.Request(url, headers=head)
html = ""
try:
response = urllib.request.urlopen(request)
html = response.read().decode("utf-8")
except urllib.error.URLError as e:
if hasattr(e, "code"):
print(e.code)
if hasattr(e, "reason"):
print(e.reason)
return html

head用于模拟浏览器头部信息,相当于我们在模拟人工查询网页时目标服务器会接受到的信息

如果不写head可能会被认出来是爬虫,导致错误

逐一解析数据:

解析数据用到了BeautifulSoup这个库(爬虫必备库)

用正则表达式去匹配:

1
2
3
4
5
6
7
findLink = re.compile(r'<a href="(.*?)">')  # 创建正则表达式对象,标售规则   影片详情链接的规则
findImgSrc = re.compile(r'<img.*src="(.*?)"', re.S)
findTitle = re.compile(r'<span class="title">(.*)</span>')
findRating = re.compile(r'<span class="rating_num" property="v:average">(.*)</span>')
findJudge = re.compile(r'<span>(\\d*)人评价</span>')
findInq = re.compile(r'<span class="inq">(.*)</span>')
findBd = re.compile(r'<p class="">(.*?)</p>', re.S)

一些解释:

  • r'' :用于表示python的原始字符串,避免 \\ 作为转义符干扰,让正则表达式更易读
  • <p class="">
    • 这里匹配 <p>标签,要求 class属性为空
    • 如果网页class属性省略了,还需要调整匹配方式
  • (.*?)
    • 小括号表示一个捕获组,可以提取匹配到的内容
    • .*?
      • . 匹配任意字符
      • *? 非贪婪匹配,匹配尽可能少的字符,遇到 </p>(结束标签)就停止
      • * 表示匹配任意次数,但 ? 让它变成非贪婪模式
  • re.S (re.DOTALL)
    • . 可以匹配换行符,<p>标签内部文本可以是多行的
    • 如果没有 re.S,换行符 \\n可能会导致匹配失败

保存数据:

1
2
saveData(datalist,savepath)      #2种存储方式可以只选择一种
# saveData2DB(datalist,dbpath)

保存数据可以选择保存到 xls表(xlwt库支持),或者保存到sqlite数据库(sqlite3库支持)

  • 保存到xls:
1
2
3
4
5
6
7
8
9
10
11
12
13
def saveData(datalist,savepath):
print("save.......")
book = xlwt.Workbook(encoding="utf-8",style_compression=0) #创建workbook对象
sheet = book.add_sheet('豆瓣电影Top250', cell_overwrite_ok=True) #创建工作表
col = ("电影详情链接","图片链接","影片中文名","影片外国名","评分","评价数","概况","相关信息")
for i in range(0,8):
sheet.write(0,i,col[i]) #列名
for i in range(0,250):
# print("第%d条" %(i+1)) #输出语句,用来测试
data = datalist[i]
for j in range(0,8):
sheet.write(i+1,j,data[j]) #数据
book.save(savepath) #保存

sheet = book.add_sheet('豆瓣电影Top250', cell_overwrite_ok=True) #创建工作表

创建工作表

col = ("电影详情链接","图片链接","影片中文名","影片外国名","评分","评价数","概况","相关信息")

创建列

But!这个xls有点老旧的样子,在vscode和wps都没办法打开文件,所以叫ai重写了一下。改为使用openpyxl库

1
2
3
4
5
6
7
8
9
10
11
12
13
def saveData(datalist, savepath):
print("正在保存数据......")
wb = openpyxl.Workbook()
sheet = wb.active
sheet.title = "豆瓣电影Top250"
col = ["电影详情链接", "图片链接", "影片中文名", "影片外国名", "评分", "评价数", "概况", "相关信息"]
sheet.append(col)

for data in datalist:
sheet.append(data)

wb.save(savepath)

开展:

(一)分析目标网站

在编写爬虫前,先查看目标网站的robots.txt文件,了解网站允许的爬取范围。同时,使用浏览器开发者工具(F12)检查页面结构,分析数据所在位置和标签特征。

(二)发送请求

利用工具向目标网站发送HTTP请求,获取网页内容。在发送请求时,要注意设置合适的请求头,模拟真实浏览器行为,避免被网站识别为爬虫。

(三)解析内容

将获取到的网页内容进行解析,提取所需数据。根据网页结构和数据特点,选择合适的解析工具和方法。

(四)存储数据

将提取到的数据存储到本地文件或数据库中,方便后续使用和分析。根据数据量和使用需求,选择合适的存储方式。

(五)处理动态内容

对于动态生成的网页内容,需要使用专门的工具模拟浏览器操作,获取完整的页面数据。在处理动态内容时,要注意页面加载时间和操作的稳定性。

(六)反爬策略应对

网站为了保护自身数据,会采取各种反爬措施。可以通过设置请求头、使用代理IP、添加延迟等方式应对反爬策略,确保爬虫的稳定运行。

Requests库

七个主要方法

req.request() 构造一个请求

req.get() 获取HTML网页

req.head() 获取HTML网页头信息

req.post() 向HTML网页提交POST请求

req.put() 提交PUT请求

req.patch() 提交局部修改请求

req.delete() 提交删除请求

正则表达式

$ 表示结束匹配

元字符 含义 示例
. 匹配任意一个字符(除了换行符 \\n a.b匹配 "acb""a2b"
^ 匹配行首 ^abc只能匹配 "abc"在字符串开头的情况
$ 匹配行尾 xyz$只能匹配 "xyz"在字符串结尾的情况
* 匹配0 或多次前面的字符 ab*c匹配 "ac""abc""abbc"
+ 匹配1 或多次前面的字符 ab+c匹配 "abc""abbc",但不匹配 "ac"
? 匹配0 或 1 次前面的字符 ab?c匹配 "ac""abc"
{m,n} 匹配m 到 n 次前面的字符 ab{1,3}c匹配 "abc""abbc""abbbc"
符号 含义 示例
\\d 匹配数字 (等价于 [0-9] \\d+匹配 "123"
\\D 匹配非数字 (等价于 [^0-9] \\D+匹配 "abc"
\\w 匹配单词字符 (字母、数字、下划线 a-zA-Z0-9_ \\w+匹配 "hello123"
\\W 匹配非单词字符 (等价于 [^a-zA-Z0-9_] \\W+匹配 "$#@"
\\s 匹配空白字符 (空格、Tab、换行) \\s+匹配 " "
\\S 匹配非空白字符 \\S+匹配 "hello"

.* 默认匹配尽可能多的字符:默认为贪婪匹配

使用 *?+? 让匹配 尽可能少 :非贪婪匹配

Python 正则表达式常用方法

方法 功能
re.match(pattern, string) 从头匹配字符串
re.search(pattern, string) 搜索第一个匹配项
re.findall(pattern, string) 返回所有匹配项 (列表)
re.finditer(pattern, string) 以迭代器返回所有匹配项
re.sub(pattern, repl, string) 替换匹配项
re.split(pattern, string) 分割字符串

用爬虫爬idol的照片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import requests
from bs4 import BeautifulSoup
import time
import random
import os

def fetch_images(keyword, num_images=10):
# 随机 User-Agent 列表
user_agents = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Safari/605.1.15',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0',
'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1'
]

# 创建会话
session = requests.Session()

# Bing图片搜索URL
url = f'<https://cn.bing.com/images/search?q={keyword}&form=HDRSC2&first=1>'

# 随机选择一个 User-Agent
headers = {
'User-Agent': random.choice(user_agents),
'Referer': '<https://cn.bing.com/>'
}

# 发送请求
try:
print("开始发送请求...")
response = session.get(url, headers=headers, timeout=10)
response.raise_for_status() # 检查请求是否成功
print("请求成功,状态码:", response.status_code)
except requests.exceptions.RequestException as e:
print(f'请求失败: {e}')
return

# 解析页面
soup = BeautifulSoup(response.text, 'html.parser')

# 提取图片URL
image_urls = []
for img in soup.find_all('img', class_='mimg'):
img_url = img.get('src')
if img_url and img_url.startswith(('http://', 'https://')): # 过滤无效 URL
image_urls.append(img_url)

# 创建保存图片的文件夹
if not os.path.exists('images'):
os.makedirs('images')

# 下载图片
for i, img_url in enumerate(image_urls[:num_images]): # 只取前 num_images 张
try:
# 随机延时 2~5 秒
time.sleep(random.uniform(2, 5))

# 随机选择一个 User-Agent
headers['User-Agent'] = random.choice(user_agents)

# 发送请求
print(f"开始下载图片 {i+1}: {img_url}")
response = session.get(img_url, headers=headers, timeout=10)
response.raise_for_status()

# 保存图片
with open(f'images/image_{i}.jpg', 'wb') as f:
f.write(response.content)
print(f'下载完成: image_{i}.jpg')
except requests.exceptions.RequestException as e:
print(f'下载失败: {e}')

def main():
keyword = '姚琛'
num_images = 10
print(f"开始抓取 {num_images} 张 '{keyword}' 的图片...")
fetch_images(keyword, num_images)
print("程序运行结束。")

if __name__ == "__main__":
main()

结果:

笔记参考&资料:

https://blog.csdn.net/bookssea/article/details/107309591

https://www.runoob.com/python3/python-spider-beautifulsoup.html

https://github.com/Ehco1996/Python-crawler?tab=readme-ov-file


爬虫
https://pqcu77.github.io/2025/03/02/爬虫/
作者
linqt
发布于
2025年3月2日
许可协议