网络基础概述
HTTP 协议
HyperText Transfer Protocol,超文本传输协议,是浏览器与服务器的文本交互协议
HTTPS 协议
基于 HTTP 协议,是 HTTP 的安全形式,HTTPS 网站是通过 SSL/TLS 加密流量的网站
要升级 https 协议,需要到 CA 进行认证,它会生成并颁发 SSL 证书
免费证书较少,所以通常需要一定费用
CA(Certificate Authority)
颁发数字证书的机构
了解 HTML 和 CSS
HTML 定义页面结构,CSS 负责样式渲染。了解标签层级与选择器是解析页面的前提
爬取核心技术栈
一些网站为了防止爬虫,会有一些检查机制
我们需要添加请求头 header,将 Python 伪装成浏览器
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
headers = {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9",
"Cache-Control": "max-age=0",
"Connection": "keep-alive",
"Host": "example.com",
"Referer": "https://example.com",
"Upgrade-Insecure-Requests": "1",
"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"
}
|
requests 基础示例
1
2
3
4
5
6
7
8
|
import re, requests
resp = requests.get(url, headers=headers, timeout=10)
print("HTTP 状态码:", resp.status_code)
# 正则提取示例(根据实际页面结构调整)
title = re.search(r'<h1[^>]*>(.*?)</h1>', resp.text).group(1)
playinfo = re.search(r'window.__playinfo__\s*=\s*(\{.*?\});', resp.text).group(1)
|
BeautifulSoup(HTML 解析)
BeautifulSoup 是 HTML 解析库之一
其中 lxml,优点是处理速度快
而 html.parser 是自带的,不用安装比较方便
-
假设要获取到标签 <div class="col-md-1"> 中的内容
1
2
3
4
5
6
7
8
9
10
11
|
import requests
from bs4 import BeautifulSoup
response = requests.get(url, headers=headers)
# 通过美味汤解析响应的文本内容,并寻找对应 class 的 div 标签
rows = BeautifulSoup(response.text, 'lxml').find_all(
name = 'div',
attrs = {'class': 'col-md-1'}
)
print(rows) # 返回一个列表
|
soup.find().get_text() 只返回第一个匹配到的对象
可以将获取到的数据先存储为列表,之后再转为 pd.DataFrame
再转为表格文件 df.to_excel(filename, index=False, encoding='utf-8')
-
子节点、兄弟节点
1
2
3
4
5
6
7
|
# 打印 table 标签且 id 等于 giftList 下的子节点
response = requests.get(url, headers=headers)
bsObj = BeautifulSoup(response.text, 'html.parser')
for child in bsObj.find("table", {"id": "giftList"}).children:
print(child)
# 同理有处理父标签的方法 .parent
|
1
2
3
|
# 获取 table#giftList -> tr 的后一兄弟标签
bsObj.find("table", {"id": "giftList"}).tr.next_siblings
# 同理有 previous_siblings() 获取前一兄弟标签
|
-
获取标签的属性
1
2
|
# .attrs 返回一个字典
Tag.attrs["src"]
|
JSON 数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import json
# loads 方法可以理解为
# 字符串类型 转为 字典
# 注意里面的键值用的是【双引号】
json_data = '{"name": "Mike", "age": "30"}'
dict_data = json.loads(json_data)
# dumps 方法可以理解为
# 字典 转为 字符串类型
dict_data = {"name": "Mike", "age": "30"}
json_data = json.dumps(dict_data, ensure_ascii=False, indent=2)
|
动态内容获取
selenium 可以模拟浏览器行为
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# 模块导入
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver import ActionChains
import pyautogui
from lxml import html
# driver 的路径
DRIVER_PATH = "D:/python/msedgedriver.exe"
|
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
|
driver = webdriver.Edge(DRIVER_PATH)
# 最大化窗口
driver.maximize_window()
# 自定义窗口大小
driver.set_window_size(1280, 720)
# 设置等待时间
# 设置最长等待时间为 20 秒,且每 1 秒就检测一下网页是否加载完全
wait = WebDriverWait(driver, 20, 1)
# 向指定的 url 发送 get 请求
driver.get(url)
# 也可以利用 BeautifulSoup 对获取到的 html 内容进行解析
# html = driver.page_source
# soup = BeautifulSoup(html, 'html.parser')
# 查找元素(直接查找)
article_loc = driver.find_element(by=By.XPATH, value="//*[@id='tbody']/tr[1]/td[1]/a")
# 查找元素(等到元素都加载完后再查找)
article_loc = wait.until(
EC.presence_of_element_located((By.XPATH, "//*[@id='tbody']/tr[1]/td[1]/a"))
)
# 获取文章的链接
article_link = article_loc.get_attribute(name='href')
|
1
2
3
4
5
6
7
8
9
|
# 模拟鼠标的移动和点击
ActionChains(driver).move_to_element(article_loc).perform()
article_loc.click()
# 模拟键盘的输入
ActionChains(driver).send_keys(Keys.SPACE).perform() #传入空格键
# 控制鼠标点击相应坐标
pyautogui.moveTo(1380, 650)
pyautogui.click() #控制鼠标点击
|
1
2
3
4
5
6
|
# 获取当前窗口
currentwindow = driver.current_window_handle
# 获取所有窗口,返回一个列表,里面放着一些窗口对象
all_window = driver.window_handles
# 切换窗口
driver.switch_to.window('某个窗口对象')
|
数据持久化
CSV / Excel
-
csv 文件的写入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import csv
# 创建 CSV 文件,并写入表头信息
# w+ 表示创建并写入
with open('新建.csv', 'w+', newline='', encoding='utf-8-sig') as fp:
writer = csv.writer(fp)
writer.writerow(("标题", "时间", "URL", "正文内容", "来源"))
# 将数据写入 csv 文件
# a+ 表示追加写入
with open('新建.csv', 'a+', newline='', encoding='utf-8-sig') as fp:
writer = csv.writer(fp)
writer.writerow((title, publish_time, article_link, article_text, source))
|
newline 参数
用于控制行尾的行为,保持 CSV 文件中的换行符一致性
不同操作系统使用不同的行尾符号来表示换行
在 Windows 中使用 \r\n,在 Unix/Linux 中使用 \n
设置 newline='' 来告诉 Python 在写入文件时 不要自动插入额外的换行符
JSON
1
2
3
4
5
|
import json
json_str = json.dumps(dict_data, ensure_ascii=False, indent=2)
with open("data.json", "w", encoding="utf-8") as f:
f.write(json_str)
|
反爬虫策略
| 策略 |
关键实现 |
参考 |
| User-Agent 轮换 |
随机挑选 User-Agent 列表 |
|
| 代理 IP 池 |
使用住宅/付费代理,降低单 IP 风险 |
|
| 完整请求头 |
包含 Referer、Accept-Language 等 |
|
| 动态渲染 |
Selenium/Playwright 执行 JS,获取完整页面 |
|
| 加密参数 |
逆向 JS 加密或使用 js2py 模拟 |
|
| 验证码 |
手工识别或接入第三方识别服务 |
|
| 请求频率控制 |
随机延时 1‑3 s,避免触发 IP 封禁 |
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import random, requests
USER_AGENTS = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/108.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/108.0.0.0 Safari/537.36",
# 更多...
]
PROXIES = [
{"http": "http://user:pass@proxy1:8080", "https": "https://user:pass@proxy1:8080"},
{"http": "http://user:pass@proxy2:8080", "https": "https://user:pass@proxy2:8080"},
]
def fetch(url):
hdr = {"User-Agent": random.choice(USER_AGENTS)}
prx = random.choice(PROXIES)
resp = requests.get(url, headers=hdr, proxies=prx, timeout=10)
return resp.text
|
| 阶段 |
项目示例 |
目标技能 |
| 入门 |
爬取天气/新闻头条 |
基本请求、解析、存储 |
| 进阶 |
电商商品信息抓取(含登录) |
代理、验证码、动态渲染 |
| 高级 |
社交媒体舆情分析(大规模) |
分布式爬虫、反爬全链路 |
建议:从小项目开始,逐步加入代理、Selenium、加密处理等高级技巧,形成完整的爬虫工程能力。
法律和道德
了解版权法、隐私法等
在爬取数据时遵守道德规范,不滥用爬虫技术
- 知识产权
- 商标:TM 或者是 R 加一个圈(™)
- 版权:C 加一个圈(©)
- 专利
- 不控制速度的话会造成的问题
1、过度消耗别人的服务器资源,是非法的
2、可能导致一个小型的网站下线,是不道德的
一般大型网站根目录会有 robots.txt 文件
用来禁止使用爬虫采集网页来收集网站信息的机器人
之所以不让爬取,是因为其网站本身提供了 API
通过 API 接口可以更容易控制数据内容,也可以通过对用户授权获利
robots.txt 文件没有标准的语法格式,并不是强制性约束