文章目录
- [1. 网络爬虫简介](#1. 网络爬虫简介)
-
- [1.1. 什么是网络爬虫](#1.1. 什么是网络爬虫)
- [1.2. 网络爬虫工作原理](#1.2. 网络爬虫工作原理)
- [1.3. 常见的 Python 爬虫库介绍](#1.3. 常见的 Python 爬虫库介绍)
- [1.4. 网络爬虫需要注意的重要事项](#1.4. 网络爬虫需要注意的重要事项)
-
- [1.4.1. 网络爬虫需要注意的重要事项](#1.4.1. 网络爬虫需要注意的重要事项)
- [1.4.2. 爬虫与反爬的攻防关系](#1.4.2. 爬虫与反爬的攻防关系)
- [2. 如何查看和遵守 robots.txt](#2. 如何查看和遵守 robots.txt)
-
- [2.1. 如何查看 robots.txt 文件](#2.1. 如何查看 robots.txt 文件)
-
- [2.1.1. 直接访问: 将网址后面加上"/robots.txt"](#2.1.1. 直接访问: 将网址后面加上"/robots.txt")
- [2.1.2. 通过 requests 代码查看](#2.1.2. 通过 requests 代码查看)
- [2.2. robots.txt 文件典型内容示例](#2.2. robots.txt 文件典型内容示例)
- [2.3. robots.txt 文件分析图解](#2.3. robots.txt 文件分析图解)
- [3. Python 爬虫操作](#3. Python 爬虫操作)
-
- [3.1. 爬虫请求](#3.1. 爬虫请求)
-
- [3.1.1. 请求方式](#3.1.1. 请求方式)
- [3.1.2. 请求 URL](#3.1.2. 请求 URL)
- [3.1.3. 请求头](#3.1.3. 请求头)
- [3.1.4. 请求体](#3.1.4. 请求体)
- [3.2. 爬虫响应](#3.2. 爬虫响应)
-
- [3.2.1. 响应状态码](#3.2.1. 响应状态码)
- [3.2.2. respone header](#3.2.2. respone header)
- [3.2.3. preview 就是网页源代码](#3.2.3. preview 就是网页源代码)
- [4. 基础爬虫开发](#4. 基础爬虫开发)
-
- [4.1. 爬虫实例1](#4.1. 爬虫实例1)
- [4.2. 爬虫实例2](#4.2. 爬虫实例2)
-
- [4.2.1. 单线程版](#4.2.1. 单线程版)
- [4.2.2. 多线程版](#4.2.2. 多线程版)
1. 网络爬虫简介
参考:https://juejin.cn/post/7494635102174036003
1.1. 什么是网络爬虫
网络爬虫(Web Crawler)是一种自动获取网页内容的程序。它可以访问网站,抓取页面内容,并从中提取有价值的数据。在信息爆炸的时代,爬虫技术可以帮助我们高效地收集、整理和分析互联网上的海量数据。
1.2. 网络爬虫工作原理
网络爬虫虽然种类多样,但基本工作原理是相似的。下图展示了爬虫的典型工作流程:
网络爬虫的工作流程通常遵循一个循环往复的过程,主要包括以下几个环节:
初始化种子URL: 爬虫从一组预定义的起始 URL(称为种子URL)开始工作。这些 URL 是爬取过程的入口点,类似于探索迷宫的起点。
URL 队列管理: 爬虫维护一个待爬取的 URL 队列。初始时,队列中只有种子 URL,随着爬取过程的推进,新发现的 URL 会不断加入队列。
URL 调度器: 负责从 URL 队列中选择下一个要爬取的 URL。调度器会考虑各种因素,如 URL 优先级、访问频率限制、网站礼仪(robots.txt)等。
网页下载: 爬虫向目标 URL 发送 HTTP 请求,获取网页内容。这一步可能会处理各种 HTTP 状态码、重定向、超时等情况。
内容解析: 获取到网页内容后,爬虫会解析 HTML/XML 结构,提取有价值的数据。常用的解析方法包括正则表达式、XPath、CSS选择器或专门的解析库(如BeautifulSoup)。
数据过滤与存储: 对提取的数据进行清洗、去重、格式化等处理,然后存储到文件、数据库或其他存储系统中。
URL提取: 从已下载的页面中提取新的URL链接,这些新URL经过筛选后(去除重复、不符合规则的URL)加入到URL队列中,等待后续爬取。
循环迭代: 重复上述过程,直到达到预定的终止条件,如队列为空、达到最大爬取数量或时间限制等。
在实际应用中,爬虫系统还会增加很多功能模块,如反爬处理、分布式协作、失败重试、数据验证等,以提高爬取的效率、稳定性和准确性。
1.3. 常见的 Python 爬虫库介绍
为了应对不同的爬取需求和反爬挑战,Python生态系统提供了多种爬虫相关的库。以下是一些最常用的工具:
库名 | 特点 | 适用场景 |
---|---|---|
Requests | 简单易用的 | HTTP库基础网页获取 |
BeautifulSoup | HTML/XML解析器 | 静态网页内容提取 |
Scrapy | 全功能爬虫框架 | 大型爬虫项目 |
Selenium | 浏览器自动化工具 | 需要JavaScript渲染的网页 |
Pyppeteer | Puppeteer的Python版本 | 复杂的动态网页 |
lxml | 高效的XML/HTML解析器 | 需要高性能解析的场景 |
PyQuery | 类 jQuery 语法的解析库 | 熟悉 jQuery 的开发者 |
aiohttp | 异步HTTP客户端/服务器 | 高并发爬虫 |
掌握了这些工具后,我们就能应对各种网页爬取的需求。爬虫技术的应用场景也非常广泛。
1.4. 网络爬虫需要注意的重要事项
1.4.1. 网络爬虫需要注意的重要事项
法律与道德考量
尊重robots.txt:这是网站指定爬虫行为的标准文件,应当遵守。
识别网站的爬虫政策:有些网站明确禁止爬虫,有些则有特定的API可用。
避免过度请求:高频率的请求可能导致服务器负担过重。
遵守数据使用条款:确保你对抓取的数据的使用符合网站的条款。
注意个人隐私数据:不应爬取和存储涉及个人隐私的数据。
技术注意事项
设置合理的请求间隔:使用time.sleep()控制请求频率。
使用代理IP:避免IP被封禁。
模拟真实用户行为:添加请求头,随机调整请求间隔。
处理反爬机制:验证码识别、JavaScript渲染等。
异常处理:网络连接、解析错误等都需要妥善处理。
性能考虑
异步爬取:使用asyncio和aiohttp提高效率。
分布式爬取:对于大规模爬取任务,考虑使用多机协作。
数据存储优化:选择合适的存储方式(文件、数据库等)。
1.4.2. 爬虫与反爬的攻防关系
随着互联网数据价值的不断提升,爬虫技术与反爬技术之间形成了一种此消彼长的攻防关系。这种关系呈现出明显的阶段性特征,从最初的简单对抗发展到如今的复杂博弈。
在早期阶段,爬虫通常以简单的HTTP请求方式获取网页内容,网站则主要通过访问频率限制来防御。爬虫工程师很快发现,只需在请求中添加随机延时就能有效规避这类限制。这种基础层面的对抗促使网站开发者升级防御策略。
随着对抗升级,网站开始实施更复杂的防御措施,例如检测请求头中的用户代理信息,以及限制单一IP的访问次数。爬虫技术随之调整,不仅能够伪装请求头信息,还发展出代理IP池技术,通过不断切换IP地址来绕过访问限制。这一阶段的特点是技术门槛明显提高,双方对抗更加精细化。
当前,我们已进入高级对抗阶段。网站普遍采用验证码挑战、前端JavaScript渲染数据以及用户行为分析等技术手段。爬虫则相应发展出验证码识别、浏览器自动化以及用户行为模拟等对抗技术。例如,Selenium和Puppeteer等工具能够模拟真实浏览器环境,执行JavaScript并渲染页面,而机器学习算法则用于识别各类验证码。
这种持续升级的攻防关系,某种程度上推动了双方技术的不断创新与进步。对于数据分析工作而言,理解这种技术演进对于构建稳定的数据获取渠道至关重要。
2. 如何查看和遵守 robots.txt
作为负责任的爬虫开发者,我们应该尊重网站所有者的意愿。robots.txt 是网站根目录下的一个文本文件,用于告诉爬虫哪些页面可以爬取,哪些不可以。遵守 robots.txt 是网络爬虫的基本道德准则。
2.1. 如何查看 robots.txt 文件
2.1.1. 直接访问: 将网址后面加上"/robots.txt"
bash
https://www.baidu.com/robots.txt

2.1.2. 通过 requests 代码查看
python
import requests
def get_robots_txt(url):
# 确保URL格式正确
if not url.startswith('http'):
url = 'https://' + url
# 移除URL末尾的斜杠(如果有)
if url.endswith('/'):
url = url[:-1]
# 获取robots.txt文件
robots_url = url + '/robots.txt'
try:
response = requests.get(robots_url)
if response.status_code == 200:
print(f"成功获取 {robots_url}")
return response.text
else:
print(f"无法获取robots.txt,状态码: {response.status_code}")
return None
except Exception as e:
print(f"发生错误: {e}")
return None
# 使用示例
robots_content = get_robots_txt('www.baidu.com')
print(robots_content)

2.2. robots.txt 文件典型内容示例
javascript
User-agent: *
Disallow: /private/
Disallow: /admin/
Allow: /public/
Crawl-delay: 10
解释:
User-agent: * - 适用于所有爬虫
Disallow: /private/ - 禁止爬取/private/目录下的内容
Allow: /public/ - 允许爬取/public/目录下的内容
Crawl-delay: 10 - 建议爬虫每次请求之间间隔10秒
2.3. robots.txt 文件分析图解

理解了网站的爬取规则后,我们可以开始实际的爬虫编写。下面是一个简单的 Python 爬虫示例,展示了基本的爬取过程。
3. Python 爬虫操作
3.1. 爬虫请求
3.1.1. 请求方式
常见的请求方式:GET / POST
3.1.2. 请求 URL
url 全球统一资源定位符,用来定义互联网上一个唯一的资源 例如:一张图片、一个文件、一段视频都可以用 url 唯一确定
加载一个网页,通常都是先加载 document 文档,
在解析 document 文档的时候,遇到链接,则针对超链接发起下载图片的请求。
3.1.3. 请求头
User-agent:请求头中如果没有 user-agent 客户端配置,服务端可能将你当做一个非法用户 host;
cookies:cookie 用来保存登录信息
注意: 一般做爬虫都会加上请求头
请求头需要注意的参数:
(1)Referrer:访问源至哪里来(一些大型网站,会通过 Referrer 做防盗链策略;所有爬虫也要注意模拟)
(2)User-Agent:访问的浏览器(要加上否则会被当成爬虫程序)
(3)cookie:请求头注意携带
3.1.4. 请求体
如果是 get 方式,请求体没有内容 (get 请求的请求体放在 url 后面参数中,直接能看到)
如果是 post 方式,请求体是 format data
ps:
1、登录窗口,文件上传等,信息都会被附加到请求体内
2、登录,输入错误的用户名密码,然后提交,就可以看到 post,正确登录后页面通常会跳转,无法捕捉到 post
3.2. 爬虫响应
3.2.1. 响应状态码
200:代表成功
301:代表跳转
404:文件不存在
403:无权限访问
502:服务器错误
3.2.2. respone header
响应头需要注意的参数:
1、Set-Cookie:BDSVRTM=0; path=/:可能有多个,是来告诉浏览器,把 cookie 保存下来
2、Content-Location:服务端响应头中包含 Location 返回浏览器之后,浏览器就会重新访问另一个页面
3.2.3. preview 就是网页源代码
JSON 数据
如网页 html、图片、二进制数据等
4. 基础爬虫开发
4.1. 爬虫实例1
以下是一个基础的 Python 爬虫示例,用于爬取百度热搜榜的内容:
python
import requests
from bs4 import BeautifulSoup
# 发送HTTP请求
url = "https://top.baidu.com/board?tab=realtime"
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}
response = requests.get(url, headers=headers)
# 检查请求是否成功
if response.status_code == 200:
# 解析HTML内容
soup = BeautifulSoup(response.text, 'html.parser')
# 提取热搜标题
hot_titles = soup.select("div.c-single-text-ellipsis")
for i, title in enumerate(hot_titles, 1):
print(f"{i}. {title.text.strip()}")
else:
print(f"请求失败,状态码: {response.status_code}")
这个示例中我们使用 requests 库对百度热搜榜发起 HTTP 请求,获取页面的 HTML 内容。
然后利用 BeautifulSoup 库(这是一个强大的 HTML 解析工具,后续博客会详细介绍)对获取的内容进行解析。通过选择器定位到热搜标题所在的元素(具有"c-single-text-ellipsis"类的 div 元素),我们能够准确提取出当前的热搜话题,并按顺序打印出来。代码中还添加了请求头信息和错误处理机制,确保爬取过程更加稳定可靠。
4.2. 爬虫实例2
参考:https://cloud.tencent.com/developer/article/1934685
尚未测试
4.2.1. 单线程版
python
import re
import requests
import hashlib
import time
# respose=requests.get('http://www.xiaohuar.com/v/')
# # print(respose.status\_code)# 响应的状态码
# # print(respose.content) #返回字节信息
# # print(respose.text) #返回文本内容
# urls=re.findall(r'class="items".\*?href="(.\*?)"',respose.text,re.S) #re.S 把文本信息转换成1行匹配
# url=urls\[5\]
# result=requests.get(url)
# mp4\_url=re.findall(r'id="media".\*?src="(.\*?)"',result.text,re.S)\[0\]
#
# video=requests.get(mp4\_url)
#
# with open('D:\\\\a.mp4','wb') as f:
# f.write(video.content)
#
def get_index(url):
respose = requests.get(url)
if respose.status_code==200:
return respose.text
def parse_index(res):
urls = re.findall(r'class="items".\*?href="(.\*?)"', res,re.S) # re.S 把文本信息转换成1行匹配
return urls
def get_detail(urls):
for url in urls:
if not url.startswith('http'):
url = 'http://www.xiaohuar.com%s' %url
result = requests.get(url)
if result.status_code==200 :
mp4_url_list = re.findall(r'id="media".\*?src="(.\*?)"', result.text, re.S)
if mp4_url_list:
mp4_url = mp4_url_list[0]
print(mp4_url)
# save(mp4\_url)
def save(url):
video = requests.get(url)
if video.status_code==200:
m = hashlib.md5()
m.updata(url.encode('utf-8'))
m.updata(str(time.time()).encode('utf-8'))
filename = r'%s.mp4'% m.hexdigest()
filepath = r'D:\\\\%s'%filename
with open(filepath, 'wb') as f:
f.write(video.content)
def main():
for i in range(5):
res1 = get_index('http://www.xiaohuar.com/list-3-%s.html'% i )
res2 = parse_index(res1)
get_detail(res2)
if __name__ == '__main__':
main()
4.2.2. 多线程版
python
import re
import requests
import hashlib
import time
from concurrent.futures import ThreadPoolExecutor
p = ThreadPoolExecutor(30) #创建1个程池中,容纳线程个数为30个;
def get_index(url):
respose = requests.get(url)
if respose.status_code==200:
return respose.text
def parse_index(res):
res = res.result() # 进程执行完毕后,得到1个对象
urls = re.findall(r'class="items".\*?href="(.\*?)"', res,re.S) # re.S 把文本信息转换成1行匹配
for url in urls:
p.submit(get_detail(url)) #获取详情页 提交到线程池
def get_detail(url): # 只下载1个视频
if not url.startswith('http'):
url = 'http://www.xiaohuar.com%s' % url
result = requests.get(url)
if result.status_code==200 :
mp4_url_list = re.findall(r'id="media".\*?src="(.\*?)"', result.text, re.S)
if mp4_url_list:
mp4_url=mp4_url_list[0]
print(mp4_url)
# save(mp4_url)
def save(url):
video = requests.get(url)
if video.status_code==200:
m = hashlib.md5()
m.updata(url.encode('utf-8'))
m.updata(str(time.time()).encode('utf-8'))
filename = r'%s.mp4'% m.hexdigest()
filepath = r'D:\\\\%s'%filename
with open(filepath, 'wb') as f:
f.write(video.content)
def main():
for i in range(5):
p.submit(get_index, 'http://www.xiaohuar.com/list-3-%s.html'% i).add_done_callback(parse_index)
# 1、先把爬主页的任务(get_index)异步提交到线程池
# 2、get_index 任务执行完后,会通过回调函 add_done_callback() 数通知主线程,任务完成;
# 2、把 get_index 执行结果(注意线程执行结果是对象,调用 res=res.result() 方法,才能获取真正执行结果),当做参数传给 parse_index
# 3、parse_index 任务执行完毕后,
# 4、通过循环,再次把获取详情页 get_detail() 任务提交到线程池执行
if __name__ == '__main__':
main()