Python爬虫:开启数据抓取的奇幻之旅(一)_爬虫csdn-CSDN博客
目录
四、代码实战:开启爬虫之旅
(一)简单网页抓取
现在,让我们通过一个简单的例子来感受一下 Python 爬虫的魅力。以抓取网页标题为例,下面是完整的代码实现:
import requests
from bs4 import BeautifulSoup
def get_page_title(url):
try:
# 发送GET请求,获取网页响应
response = requests.get(url)
# 如果响应状态码为200,说明请求成功
if response.status_code == 200:
# 使用BeautifulSoup解析响应内容
soup = BeautifulSoup(response.text, 'html.parser')
# 提取网页标题
title = soup.title.string
return title
else:
print(f"请求失败,状态码:{response.status_code}")
except requests.RequestException as e:
print(f"请求发生异常:{e}")
# 测试
url = 'https://www.example.com'
title = get_page_title(url)
if title:
print(f"网页标题为:{title}")
逐行解释如下:
- import requests:导入requests库,用于发送 HTTP 请求。
- from bs4 import BeautifulSoup:从BeautifulSoup4库中导入BeautifulSoup类,用于解析 HTML 文档。
- def get_page_title(url)::定义一个名为get_page_title的函数,该函数接受一个参数url,表示要抓取的网页地址。
- response = requests.get(url):使用requests.get()方法向指定的url发送 GET 请求,并将返回的响应对象赋值给response。
- if response.status_code == 200::检查响应的状态码是否为 200,如果是,表示请求成功,继续后续操作;否则,打印请求失败的状态码。
- soup = BeautifulSoup(response.text, 'html.parser'):使用BeautifulSoup类创建一个解析器对象soup,将响应的文本内容response.text作为参数传入,并指定解析器为html.parser。
- title = soup.title.string:通过soup.title获取网页的<title>标签,然后使用.string属性获取标签中的文本内容,即网页标题。
- return title:返回提取到的网页标题。
- except requests.RequestException as e::捕获requests库在请求过程中可能抛出的异常,将异常对象赋值给e。
- print(f"请求发生异常:{e}"):打印异常信息。
- url = 'https://www.example.com':定义要抓取的网页地址。
- title = get_page_title(url):调用get_page_title函数,传入网页地址url,获取网页标题并赋值给title。
- if title::检查title是否有值,如果有,打印网页标题。
(二)爬取结构化数据
接下来,我们尝试爬取豆瓣电影 Top250 的信息,这是一个更具挑战性但也更有趣的任务。豆瓣电影 Top250 页面包含了丰富的电影信息,如电影名称、评分、评价人数等,这些信息以结构化的方式呈现,非常适合我们进行数据爬取和分析。
1.分析网页结构:
打开豆瓣电影 Top250 页面(豆瓣电影 Top 250 ),使用浏览器的开发者工具(通常按 F12 键打开),可以查看网页的 HTML 源代码。通过观察发现,每部电影的信息都包含在一个<div class="item">标签内,电影名称在<span class="title">标签中,评分在<span class="rating_num">标签中,评价人数在<span property="v:votes">标签中。
2.编写代码:
import requests
from bs4 import BeautifulSoup
def get_douban_movies():
base_url = 'https://movie.douban.com/top250?start={}&filter='
movies = []
for start in range(0, 250, 25):
url = base_url.format(start)
try:
response = requests.get(url)
if response.status_code == 200:
soup = BeautifulSoup(response.text, 'html.parser')
items = soup.find_all('div', class_='item')
for item in items:
movie = {}
# 提取电影名称
title = item.find('span', class_='title').text
movie['title'] = title
# 提取评分
rating = item.find('span', class_='rating_num').text
movie['rating'] = rating
# 提取评价人数
votes = item.find('span', property='v:votes').text
movie['votes'] = votes
movies.append(movie)
else:
print(f"请求失败,状态码:{response.status_code}")
except requests.RequestException as e:
print(f"请求发生异常:{e}")
return movies
# 测试
movies = get_douban_movies()
for movie in movies:
print(movie)
代码解释:
- base_url = '豆瓣电影 Top 250':定义基础 URL,其中{}是占位符,用于后续填充页码参数。
- movies = []:创建一个空列表,用于存储爬取到的电影信息。
- for start in range(0, 250, 25)::循环遍历页码,因为每页显示 25 部电影,所以从 0 开始,每次增加 25,直到 250。
- url = base_url.format(start):使用format()方法将页码参数填充到基础 URL 中,生成完整的 URL。
- response = requests.get(url):发送 GET 请求获取网页内容。
- if response.status_code == 200::检查请求是否成功。
- soup = BeautifulSoup(response.text, 'html.parser'):解析网页内容。
- items = soup.find_all('div', class_='item'):找到所有包含电影信息的<div class="item">标签。
- 内部循环中,通过find()方法找到对应的标签,并提取电影名称、评分和评价人数,存储在字典movie中,然后将字典添加到movies列表中。
- 最后返回movies列表,并遍历打印每部电影的信息。
(三)图片爬取与下载
图片是网页中常见的元素,爬取图片可以帮助我们收集各种图像资源。以爬取百度图片为例,下面介绍如何获取图片链接并下载图片保存到本地。
1.获取图片链接:
打开百度图片搜索页面,输入关键词进行搜索,比如 “风景”。在搜索结果页面,使用开发者工具查看网络请求,发现图片链接在img标签的src属性中,并且图片数据是通过 AJAX 请求获取的。通过分析请求 URL 和参数,可以找到获取图片数据的接口。例如,百度图片的搜索接口可能类似于:百度图片 | 免费AI图像生成工具与海量高清图平台{关键词}&pn={页码}。
2.编写代码:
import requests
import os
import re
def get_image_links(keyword, num_pages):
base_url = 'https://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&word={}&pn={}'
image_links = []
for pn in range(0, num_pages * 30, 30):
url = base_url.format(keyword, pn)
try:
response = requests.get(url)
if response.status_code == 200:
data = response.json()
for item in data['data']:
if 'hoverURL' in item:
image_links.append(item['hoverURL'])
else:
print(f"请求失败,状态码:{response.status_code}")
except requests.RequestException as e:
print(f"请求发生异常:{e}")
return image_links
def download_images(image_links, save_dir):
if not os.path.exists(save_dir):
os.makedirs(save_dir)
for i, link in enumerate(image_links):
try:
response = requests.get(link, stream=True)
if response.status_code == 200:
file_path = os.path.join(save_dir, f'image_{i}.jpg')
with open(file_path, 'wb') as f:
for chunk in response.iter_content(chunk_size=1024):
if chunk:
f.write(chunk)
print(f"下载成功:{file_path}")
else:
print(f"下载失败,状态码:{response.status_code}")
except requests.RequestException as e:
print(f"下载发生异常:{e}")
# 测试
keyword = '风景'
num_pages = 2
save_dir = 'images'
image_links = get_image_links(keyword, num_pages)
download_images(image_links, save_dir)
代码解释:
- get_image_links函数:
- base_url定义了百度图片搜索接口的基础 URL。
- 循环遍历页码,生成完整的请求 URL,发送 GET 请求获取 JSON 数据。
- 从 JSON 数据中提取图片链接,添加到image_links列表中。
- download_images函数:
- 检查保存图片的目录是否存在,不存在则创建。
- 遍历图片链接列表,发送 GET 请求获取图片数据,以流式传输的方式将图片数据写入本地文件。
- 最后,定义搜索关键词、要爬取的页数和保存目录,调用两个函数完成图片链接获取和下载。
(四)动态网页爬取
有些网页的数据是通过 JavaScript 动态加载的,普通的爬虫方法无法直接获取这些数据。这时,我们可以使用 Selenium 库来模拟浏览器操作,处理 JavaScript 渲染的页面。以爬取知乎动态内容为例,以下是具体实现方法。
1.安装 Selenium 和浏览器驱动:
首先,确保已经安装了 Selenium 库:pip install selenium。然后,根据使用的浏览器下载相应的驱动,如 Chrome 浏览器需要下载 ChromeDriver,并将其添加到系统路径中。
2.编写代码:
from selenium import webdriver
import time
def get_zhihu_content():
driver = webdriver.Chrome()
driver.get('https://www.zhihu.com')
# 模拟滚动页面,加载更多内容
for _ in range(5):
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(2)
# 获取页面源代码
page_source = driver.page_source
# 这里可以使用BeautifulSoup或其他方式进一步解析页面内容
driver.quit()
return page_source
# 测试
content = get_zhihu_content()
print(content)
代码解释:
- driver = webdriver.Chrome():创建一个 Chrome 浏览器驱动实例,用于控制浏览器。
- driver.get('https://www.zhihu.com'):使用驱动打开知乎网站。
- 循环中,driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")使用 JavaScript 脚本将页面滚动到底部,模拟用户操作,加载更多动态内容。time.sleep(2)用于等待页面加载完成。
- page_source = driver.page_source:获取浏览器当前页面的源代码。
- driver.quit():关闭浏览器驱动。
- 最后返回页面源代码并打印,后续可以使用BeautifulSoup等库对页面源代码进行解析,提取所需的动态内容。
五、爬虫进阶技巧:突破重重关卡
(一)应对反爬虫机制
在爬虫的征程中,我们并非总是一帆风顺,网站为了保护自身的数据和服务器资源,往往会设置各种反爬虫机制,这就像是一道道坚固的防线,阻挡着爬虫的前进。但只要掌握了正确的策略,我们就能巧妙地突破这些防线。
1.设置请求头:请求头就像是爬虫的 “伪装”,它可以让爬虫看起来更像一个真实的用户。网站通常会通过检查请求头中的User - Agent字段来判断请求是否来自爬虫。User - Agent包含了浏览器类型、版本、操作系统等信息。例如,我们可以将User - Agent设置为 Chrome 浏览器的标识:
import requests
headers = {
'User - Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}
response = requests.get(url, headers = headers)
除了User - Agent,还可以设置其他请求头字段,如Referer(表示请求的来源页面)、Accept(表示客户端接受的内容类型)等,使请求头更加逼真。
2.控制访问频率:如果爬虫过于频繁地访问网站,很容易被网站察觉并封禁。为了避免这种情况,我们需要控制爬虫的访问频率。可以使用time.sleep()函数在每次请求之间添加一定的时间间隔。例如,每 5 秒发送一次请求:
import requests
import time
urls = ['https://www.example1.com', 'https://www.example2.com', 'https://www.example3.com']
for url in urls:
response = requests.get(url)
# 处理响应
time.sleep(5)
为了使爬虫的行为更加自然,还可以设置随机的延迟时间,模拟人类用户的浏览习惯:
import requests
import time
import random
urls = ['https://www.example1.com', 'https://www.example2.com', 'https://www.example3.com']
for url in urls:
response = requests.get(url)
# 处理响应
sleep_time = random.uniform(1, 3) # 随机延迟1到3秒
time.sleep(sleep_time)
3.使用代理 IP:当爬虫的 IP 地址被网站封禁时,使用代理 IP 是一个有效的解决办法。代理 IP 就像是一个中间人,爬虫通过代理 IP 向网站发送请求,网站看到的是代理 IP 的地址,而不是爬虫的真实 IP 地址。这样,我们可以通过更换代理 IP 来继续访问网站。
可以使用一些免费或付费的代理 IP 服务,也可以自己搭建代理服务器。在 Python 中,使用requests库设置代理 IP 非常简单:
import requests
proxies = {
'http': 'http://your_proxy_ip:port',
'https': 'https://your_proxy_ip:port'
}
response = requests.get(url, proxies = proxies)
为了提高爬虫的稳定性和效率,还可以建立代理 IP 池,从代理 IP 池中随机选择代理 IP 进行请求。
(二)模拟登录
有些网站的数据需要用户登录后才能访问,这时我们就需要让爬虫模拟用户登录的过程。以登录微博为例,来详细讲解模拟登录的实现方法。
- 分析登录过程:打开微博登录页面,使用浏览器的开发者工具(F12),在 “Network” 选项卡中查看登录请求。可以发现,登录请求是一个 POST 请求,请求的 URL 为登录接口地址,请求体中包含了用户名、密码、验证码(如果有)等参数。同时,登录过程可能还涉及到一些加密和验证机制,比如用户名和密码可能会被加密后发送,服务器会对验证码进行验证等。
- 构造登录请求:在 Python 中,使用requests库来构造登录请求。首先,需要获取登录所需的参数,如用户名、密码等。然后,设置请求头,模拟浏览器行为。最后,发送 POST 请求,将参数传递给登录接口。
以下是一个简单的模拟登录微博的示例代码(假设没有验证码):
import requests
import base64
import rsa
import binascii
def get_server_info():
# 获取服务器信息,如servertime, nonce, pubkey等
prelogin_url = 'https://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack&su=&rsakt=mod&checkpin=1&client=ssologin.js(v1.4.19)&_=1630000000000'
response = requests.get(prelogin_url)
data = eval(response.text.split('(')[1].split(')')[0])
return data['servertime'], data['nonce'], data['pubkey']
def encode_username(username):
# 用户名进行base64编码
return base64.b64encode(username.encode('utf - 8'))[: - 1]
def encode_password(password, servertime, nonce, pubkey):
# 密码进行RSA加密
rsa_key = rsa.PublicKey(int(pubkey, 16), 65537)
code_str = f'{servertime}\t{nonce}\n{password}'
crypto = rsa.encrypt(code_str.encode('utf8'), rsa_key)
return binascii.b2a_hex(crypto).decode()
def login(username, password):
servertime, nonce, pubkey = get_server_info()
su = encode_username(username)
sp = encode_password(password, servertime, nonce, pubkey)
login_url = 'https://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.19)'
headers = {
'User - Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'Referer': 'https://weibo.com/'
}
data = {
'su': su,
'sp': sp,
'servertime': servertime,
'nonce': nonce,
'rsakv': '1330428213',
'entry': 'weibo',
'wentry': '',
'loginfrom': '',
'client': 'ssologin.js(v1.4.19)',
'code': '',
'qq': '',
'hff': '',
'hfp': ''
}
session = requests.Session()
response = session.post(login_url, headers = headers, data = data)
if response.status_code == 200:
print('登录成功')
return session
else:
print('登录失败')
return None
# 测试
username = 'your_username'
password = 'your_password'
session = login(username, password)
if session:
# 使用session进行后续请求,如访问个人主页
home_url = 'https://weibo.com/u/your_user_id'
response = session.get(home_url)
print(response.text)
3.处理验证码:如果登录过程中需要验证码,处理起来会稍微复杂一些。对于简单的图形验证码,可以使用光学字符识别(OCR)技术来识别,比如使用pytesseract库。对于复杂的验证码,如滑动验证码、点选验证码等,可能需要借助第三方打码平台,如超级鹰、云打码等。这些平台提供了相应的 API,我们可以将验证码图片上传到平台,平台会返回识别结果。
(三)使用 Scrapy 框架
Scrapy 是一个功能强大的爬虫框架,它为我们提供了一套完整的爬虫解决方案,大大简化了爬虫的开发过程。与传统的使用requests和BeautifulSoup进行爬虫开发相比,Scrapy 具有更高的效率、更好的可扩展性和更强大的功能。
1.Scrapy 框架的优势:
- 异步处理:Scrapy 使用 Twisted 异步网络库,可以同时处理多个网页请求,大大提高了爬取速度。这就好比一个勤劳的工人,能够同时处理多项任务,而不是一次只能做一件事,从而大大提高了工作效率。
- 中间件系统:Scrapy 提供了丰富的中间件系统,允许用户自定义处理请求和响应的过程。通过中间件,我们可以方便地实现设置请求头、使用代理 IP、处理 Cookies 等功能,就像在生产线上添加了各种自动化的工具,使整个流程更加灵活和高效。
- 数据管道:Scrapy 的数据管道可以轻松地处理爬取到的数据,支持多种输出格式(如 JSON、CSV 等),并且可以方便地将数据存储到数据库中。这就像是一个智能的仓库管理系统,能够对货物进行分类、整理和存储,让我们的数据处理更加便捷。
- 内置选择器:Scrapy 内置了强大的选择器,使用 CSS 和 XPath 表达式来提取网页中的数据,比传统的正则表达式更加简洁和高效。就像一把精准的手术刀,能够在复杂的网页结构中快速准确地切割出我们需要的数据。
2.创建项目:使用 Scrapy 创建一个新项目非常简单,打开命令行,输入以下命令:
scrapy startproject myproject
这将创建一个名为myproject的项目,并生成一系列的文件和目录结构,包括settings.py(配置文件)、items.py(定义数据结构)、pipelines.py(数据处理管道)、spiders目录(存放爬虫代码)等。
3.定义爬虫:在spiders目录下创建一个爬虫文件,例如example_spider.py,定义一个爬虫类,继承自scrapy.Spider。爬虫类需要定义name(爬虫名称)、allowed_domains(允许爬取的域名)、start_urls(起始 URL 列表)和parse方法(解析响应内容)。
以下是一个简单的 Scrapy 爬虫示例,用于爬取豆瓣电影 Top250 的信息:
import scrapy
class DoubanMovieSpider(scrapy.Spider):
name = 'douban_movie'
allowed_domains = ['movie.douban.com']
start_urls = ['https://movie.douban.com/top250?start=0&filter=']
def parse(self, response):
for item in response.css('div.item'):
yield {
'title': item.css('span.title::text').get(),
'rating': item.css('span.rating_num::text').get(),
'votes': item.css('span.votes::text').get()
}
next_page = response.css('span.next a::attr(href)').get()
if next_page is not None:
yield response.follow(next_page, self.parse)
4.解析数据:在parse方法中,使用 Scrapy 的选择器来解析响应内容。选择器支持 CSS 和 XPath 表达式,通过这些表达式可以轻松地定位和提取网页中的数据。例如,response.css('span.title::text').get()表示选择所有<span class="title">标签中的文本内容;response.xpath('//span[@class="rating_num"]/text()').get()表示使用 XPath 表达式选择所有 class 为rating_num的<span>标签中的文本内容。
5.存储数据:Scrapy 的数据管道负责处理爬取到的数据,可以将数据保存为 JSON、CSV 等格式,也可以将数据存储到数据库中。在pipelines.py文件中定义数据处理管道类,实现process_item方法,在该方法中对数据进行处理和存储。
以下是一个将数据保存为 JSON 文件的数据管道示例:
import json
class JsonPipeline:
def __init__(self):
self.file = open('movies.json', 'w', encoding='utf - 8')
def process_item(self, item, spider):
line = json.dumps(dict(item), ensure_ascii=False) + '\n'
self.file.write(line)
return item
def close_spider(self, spider):
self.file.close()
在settings.py文件中,将定义的数据管道添加到ITEM_PIPELINES设置中:
ITEM_PIPELINES = {
'myproject.pipelines.JsonPipeline': 300,
}
通过以上步骤,我们就可以使用 Scrapy 框架构建一个功能强大的爬虫,高效地爬取和处理网页数据。
六、法律与道德红线:不可逾越的边界
在 Python 网络爬虫的精彩世界里,我们尽情探索数据的宝藏,但必须时刻牢记,有一些红线是绝对不可逾越的,那就是法律与道德的边界。逾越这些边界,可能会带来严重的后果,不仅会损害他人的权益,还可能让自己陷入法律的困境。
(一)遵守 Robots 协议
Robots 协议,全称为 “网络爬虫排除标准”(Robots Exclusion Protocol),是一种位于网站根目录下的 robots.txt 文件,它就像是网站给爬虫们立下的 “规矩”。这个文件以一种简单易懂的文本格式,清晰地告诉爬虫哪些页面可以抓取,哪些页面禁止访问 。例如,一个常见的 robots.txt 文件可能包含以下内容:
User-agent: *
Disallow: /admin/
Disallow: /private/
Allow: /public/
在这段配置中,User-agent: *表示这个规则适用于所有的爬虫程序;Disallow: /admin/和Disallow: /private/则明确禁止爬虫访问/admin/和/private/目录下的页面,因为这些页面可能包含敏感信息,如网站的管理后台、用户的私人数据等;Allow: /public/则允许爬虫访问/public/目录下的页面,这些通常是网站希望被公开抓取和索引的内容。
遵守 Robots 协议是爬虫开发者应遵循的基本道德准则,也是许多国家和地区法律的要求。它不仅体现了对网站所有者意愿的尊重,也有助于维护网络生态的平衡和稳定。如果爬虫无视 Robots 协议,强行抓取被禁止的页面,就好比擅自闯入他人的私人领地,不仅可能导致网站服务器负载过高,影响正常用户的访问,还可能引发法律纠纷。例如,曾经有搜索引擎因为违反 Robots 协议,抓取了某些网站禁止访问的内容,被网站所有者起诉,最终承担了相应的法律责任。
(二)尊重网站权益
在使用爬虫时,我们要时刻保持对网站权益的尊重,不进行恶意爬取,不滥用数据。恶意爬取是指那些以破坏网站正常运行、获取不正当利益为目的的爬取行为,比如通过高频次的请求对网站进行 DDoS 攻击式的爬取,导致网站服务器瘫痪,无法为正常用户提供服务。这种行为不仅严重损害了网站的利益,也违反了法律法规,可能会面临刑事指控。
滥用数据同样是不道德且可能违法的行为。我们不能将爬取到的数据用于未经授权的商业用途,或者泄露他人的隐私信息。例如,有些不法分子利用爬虫爬取电商网站的用户评论和个人信息,然后将这些数据出售给第三方,用于精准营销甚至诈骗活动,这种行为严重侵犯了用户的隐私权,也违反了《个人信息保护法》等相关法律法规。
为了避免对网站造成不必要的负担,我们还应该合理设置爬虫的访问频率和并发请求数。可以使用time.sleep()函数在每次请求之间添加适当的时间间隔,模拟人类用户的正常浏览行为。例如:
import requests
import time
urls = ['https://www.example1.com', 'https://www.example2.com', 'https://www.example3.com']
for url in urls:
response = requests.get(url)
# 处理响应
time.sleep(2) # 每次请求后暂停2秒
(三)合法使用数据
爬取数据的最终目的必须符合法律法规的要求。数据本身具有敏感性,若将爬取的数据用于非法活动,如诈骗、侵犯个人隐私或进行不正当竞争等,将面临严重的法律后果。比如,利用爬虫获取大量用户在电商平台的消费记录,再将这些数据出售给不法分子用于精准诈骗,这不仅违反了《网络安全法》等相关法律,也严重损害了用户的合法权益。只有将爬取的数据用于合法的数据分析、学术研究或正当的商业创新等领域,才能确保爬虫行为在法律框架内进行,实现数据的合理价值。
七、总结与展望:爬虫之路的未来
在本次 Python 爬虫探索之旅中,我们从基础概念入手,逐步深入了解爬虫原理,掌握了多种网页抓取技巧与实战方法,同时也认识到法律与道德在爬虫活动中的重要约束作用。Python 爬虫作为强大的数据获取工具,其简洁的语法和丰富的库为开发者提供了广阔的施展空间。随着互联网的持续发展,数据的价值愈发凸显,爬虫技术也将在更多领域发挥重要作用,如市场调研、舆情监测、智能推荐系统数据收集等。希望读者能够以本次学习为起点,不断深入探索 Python 爬虫技术,在合法合规的前提下,挖掘更多数据背后的价值,为自身的学习、工作和研究带来新的机遇与突破。