文章目录[隐藏]
原始代码
import requests from bs4 import BeautifulSoup # 设置要爬取的页面链接 url = 'https://www.example.com/' # 发送HTTP请求 response = requests.get(url) # 检查请求是否成功 if response.status_code == 200: # 解析HTML页面 soup = BeautifulSoup(response.text, 'html.parser') # 获取页面中的所有链接 links = soup.find_all('a') # 遍历所有链接,并输出链接的文字和URL for link in links: print(link.text.strip(), link.get('href')) else: print('请求失败')
添加验证码验证
import requests from bs4 import BeautifulSoup from PIL import Image from io import BytesIO # 设置要爬取的页面链接和登录信息 url = 'https://www.example.com/login' login_data = { 'username': 'your_username', 'password': 'your_password', 'captcha': '' } # 创建一个会话 session = requests.Session() # 发送HTTP请求,获取登录页面 response = session.get(url) # 检查请求是否成功 if response.status_code == 200: # 解析HTML页面,获取验证码图片链接和其他登录信息 soup = BeautifulSoup(response.text, 'html.parser') captcha_url = soup.find('img', {'class': 'captcha-image'}).get('src') login_data['csrf_token'] = soup.find('input', {'name': 'csrf_token'}).get('value') # 发送HTTP请求,获取验证码图片 response = session.get(captcha_url) if response.status_code == 200: # 读取验证码图片并显示出来 img = Image.open(BytesIO(response.content)) img.show() # 获取用户输入的验证码 captcha = input('请输入验证码:') login_data['captcha'] = captcha # 发送HTTP请求,进行登录 response = session.post(url, data=login_data) # 检查登录是否成功 if response.status_code == 200: # 发送HTTP请求,获取需要爬取的页面 response = session.get('https://www.example.com/data') # 检查请求是否成功 if response.status_code == 200: # 解析HTML页面,提取需要的数据 soup = BeautifulSoup(response.text, 'html.parser') # TODO: 提取数据 else: print('获取页面数据失败') else: print('登录失败') else: print('获取验证码失败') else: print('获取登录页面失败')
结合前面的验证码验证,加入记录日志、数据存储和一些自动化操作的示例代码。
import requests from bs4 import BeautifulSoup import sqlite3 import logging import time from PIL import Image import pytesseract # 创建日志记录器 logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) # 创建文件处理器 file_handler = logging.FileHandler('log.txt') file_handler.setLevel(logging.DEBUG) # 创建控制台处理器 console_handler = logging.StreamHandler() console_handler.setLevel(logging.DEBUG) # 创建日志格式器 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') file_handler.setFormatter(formatter) console_handler.setFormatter(formatter) # 添加处理器到记录器 logger.addHandler(file_handler) logger.addHandler(console_handler) # 数据库连接和游标 conn = sqlite3.connect('zhihu_questions.db') cursor = conn.cursor() # 创建数据表 cursor.execute('''CREATE TABLE IF NOT EXISTS questions (id INTEGER PRIMARY KEY, title TEXT, url TEXT)''') # 获取验证码图片,并识别验证码 def get_captcha(session): captcha_url = 'https://www.zhihu.com/captcha.gif?type=login' response = session.get(captcha_url, stream=True) with open('captcha.gif', 'wb') as f: for chunk in response.iter_content(chunk_size=128): f.write(chunk) im = Image.open('captcha.gif') captcha = pytesseract.image_to_string(im) return captcha.strip() # 登录知乎并获取问题列表 def get_questions(): # 创建会话 session = requests.Session() # 获取登录页面 login_url = 'https://www.zhihu.com/signin' response = session.get(login_url) soup = BeautifulSoup(response.text, 'html.parser') # 获取登录参数 csrf_token = soup.find('input', {'name': '_csrf'})['value'] captcha = get_captcha(session) # 提交登录请求 login_data = { '_csrf': csrf_token, 'username': 'your_username', 'password': 'your_password', 'captcha': captcha } headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3', 'Referer': 'https://www.zhihu.com/', } response = session.post('https://www.zhihu.com/login/email', data=login_data, headers=headers) # 检查登录是否成功 if response.json().get('error'): logger.error('登录失败:%s' % response.json().get('error')) return # 爬取问题列表 for page in range(1, 11): url = 'https://www.zhihu.com/api/v4/questions?limit=20&offset={}&include=data[*].created,answer_count,follower_count&sort_by=updated'.format((page - 1) * 20) response = session.get(url) data = response.json().get('data') for item in data: title = item.get('title') url = 'https://www.zhihu.com/question/{}'. id = item.get('id') cursor.execute("INSERT INTO questions (id, title, url) VALUES (?, ?, ?)", (id, title, url)) logger.info('添加问题:%s' % title) time.sleep(1) # 提交事务 conn.commit() cursor.close() conn.close()
在此基础上增加一个命令行交互界面
import requests from bs4 import BeautifulSoup import sqlite3 import logging import time from PIL import Image import pytesseract import argparse # 创建日志记录器 logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) # 创建文件处理器 file_handler = logging.FileHandler('log.txt') file_handler.setLevel(logging.DEBUG) # 创建控制台处理器 console_handler = logging.StreamHandler() console_handler.setLevel(logging.DEBUG) # 创建日志格式器 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') file_handler.setFormatter(formatter) console_handler.setFormatter(formatter) # 添加处理器到记录器 logger.addHandler(file_handler) logger.addHandler(console_handler) # 数据库连接和游标 conn = sqlite3.connect('zhihu_questions.db') cursor = conn.cursor() # 创建数据表 cursor.execute('''CREATE TABLE IF NOT EXISTS questions (id INTEGER PRIMARY KEY, title TEXT, url TEXT)''') # 获取验证码图片,并识别验证码 def get_captcha(session): captcha_url = 'https://www.zhihu.com/captcha.gif?type=login' response = session.get(captcha_url, stream=True) with open('captcha.gif', 'wb') as f: for chunk in response.iter_content(chunk_size=128): f.write(chunk) im = Image.open('captcha.gif') captcha = pytesseract.image_to_string(im) return captcha.strip() # 登录知乎并获取问题列表 def get_questions(username, password): # 创建会话 session = requests.Session() # 获取登录页面 login_url = 'https://www.zhihu.com/signin' response = session.get(login_url) soup = BeautifulSoup(response.text, 'html.parser') # 获取登录参数 csrf_token = soup.find('input', {'name': '_csrf'})['value'] captcha = get_captcha(session) # 提交登录请求 login_data = { '_csrf': csrf_token, 'username': username, 'password': password, 'captcha': captcha } headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3', 'Referer': 'https://www.zhihu.com/', } response = session.post('https://www.zhihu.com/login/email', data=login_data, headers=headers) # 检查登录是否成功 if response.json().get('error'): logger.error('登录失败:%s' % response.json().get('error')) return # 爬取问题列表 for page in range(1, 11): url = 'https://www.zhihu.com/api/v4/questions?limit=20&offset={}&include=data[*].created,answer_count,follower_count&sort_by=updated'.format((page - 1) * 20) response = session.get(url) data = response.json().get('data') for item in data: title = item.get('title') url = 'https://www.zhihu.com/question/{}'.format(item.get('id')) # 保存到数据库 cursor.execute('INSERT INTO questions (title, url) VALUES (?, ?)', (title, url)) conn.commit
添加命令行交互界面的代码
import argparse # 命令行参数解析器 parser = argparse.ArgumentParser(description='爬取知乎问题列表') # 添加用户名和密码参数 parser.add_argument('username', type=str, help='知乎用户名') parser.add_argument('password', type=str, help='知乎密码') # 添加日志级别参数 parser.add_argument('--log', dest='log_level', type=str, default='info', help='日志级别,可选值:debug, info, warning, error, critical,默认值:info') # 添加数据存储路径参数 parser.add_argument('--db', dest='db_path', type=str, default='zhihu_questions.db', help='数据存储路径,默认值:zhihu_questions.db') def main(): # 解析命令行参数 args = parser.parse_args() # 设置日志级别 log_level = getattr(logging, args.log_level.upper()) logger.setLevel(log_level) file_handler.setLevel(log_level) console_handler.setLevel(log_level) # 打印日志级别 logger.info('日志级别:%s' % args.log_level) # 连接数据库 conn = sqlite3.connect(args.db_path) cursor = conn.cursor() # 创建数据表 cursor.execute('''CREATE TABLE IF NOT EXISTS questions (id INTEGER PRIMARY KEY, title TEXT, url TEXT)''') # 爬取问题列表 get_questions(args.username, args.password) # 查询问题列表 cursor.execute('SELECT * FROM questions') results = cursor.fetchall() # 打印问题列表 print('共爬取到 %d 个问题:' % len(results)) for result in results: print(result[0], result[1], result[2]) # 关闭数据库连接 conn.close() if __name__ == '__main__': main()
运行这个 Python 程序时,需要指定知乎用户名和密码作为参数。还可以使用 --log 参数指定日志级别,使用 --db 参数指定数据存储路径。
例如:
python zhihu_questions.py username@example.com password --log debug --db zhihu.db
这个程序会尝试登录知乎,然后爬取前 200 个最新的问题,并保存到 SQLite 数据库中。之后,程序会查询数据库并打印所有爬取到的问题的 id、标题和链接。同时,程序还会记录日志到 log.txt 文件中。如果登录失败或者发生其他错误,程序会记录到日志中并退出。
增加支持对爬取到的数据进行分析和可视化,例如统计问题的热度、回答数量等信息。
我们可以通过 Pandas 和 Matplotlib 这两个 Python 库对爬取到的数据进行分析和可视化。下面是一个简单的示例,展示如何使用这两个库对知乎问题的数据进行统计和可视化:
import pandas as pd import matplotlib.pyplot as plt # 读取爬取到的数据 df = pd.read_csv('zhihu_questions.csv', encoding='utf-8') # 统计问题的热度,并按照从高到低排序 df_hot = df.groupby(['title']).size().reset_index(name='hot').sort_values(by='hot', ascending=False) # 统计问题的回答数量,并按照从多到少排序 df_answer = df.groupby(['title']).sum().reset_index().sort_values(by='answer_count', ascending=False) # 绘制问题热度和回答数量的柱状图 fig, ax = plt.subplots(2, 1, figsize=(12, 8)) ax[0].bar(df_hot['title'], df_hot['hot'], color='green') ax[0].set_title('Question Hotness') ax[0].set_xticklabels(df_hot['title'], rotation=90, fontsize=8) ax[1].bar(df_answer['title'], df_answer['answer_count'], color='orange') ax[1].set_title('Question Answer Count') ax[1].set_xticklabels(df_answer['title'], rotation=90, fontsize=8) plt.tight_layout() plt.show()
这段代码会读取之前爬取到的数据,使用 Pandas 对问题的热度和回答数量进行统计和排序,然后使用 Matplotlib 绘制柱状图展示这些统计结果。这样我们就可以通过数据分析和可视化来更好地了解知乎问题的情况。