Python网络爬虫:改进与扩展,实现更稳定、更安全的抓取

在之前的代码基础上,我们可以进行一些改进和扩展,使其更稳定、更安全,并提升爬取效率。

改进和扩展点

  1. 增加日志记录:使用 logging 模块记录程序运行过程中的错误和异常信息,方便排查问题。
  2. 完善异常处理:在 crawl_website() 函数中使用 logging.error() 记录请求异常和解析异常的详细信息,避免程序崩溃。
  3. 使用并发技术提升效率:使用 concurrent.futures 模块中的 ThreadPoolExecutor 实现并发爬取多个网页,提升爬取速度。

代码示例

import requests
from bs4 import BeautifulSoup
import configparser
import concurrent.futures
import logging

def login(session, url, username, password):
    # 发送GET请求,获取登录页面的HTML内容
    response = session.get(url)
    response.raise_for_status()

    # 解析登录页面的HTML内容
    soup = BeautifulSoup(response.content, 'html.parser')

    # 获取登录表单的POST地址和对应的表单数据
    login_form = soup.find('form', id='loginForm')
    action = login_form['action']
    inputs = login_form.find_all('input')
    form_data = {input.get('name'): input.get('value') for input in inputs}

    # 更新表单数据中的用户名和密码字段
    form_data['username'] = username
    form_data['password'] = password

    # 发送POST请求进行登录
    response = session.post(url + action, data=form_data)
    response.raise_for_status()

    if '登录失败' in response.text:
        logging.error('登录失败')
        return False

    return True

def crawl_website(session, url):
    try:
        # 发送HTTP请求,获取网页内容
        response = session.get(url)
        response.raise_for_status()  # 检查请求是否成功

        # 解析HTML内容
        soup = BeautifulSoup(response.content, 'html.parser')

        # 爬取网站标题
        title = soup.title.text.strip() if soup.title else None

        # 爬取网站链接
        links = [link['href'] for link in soup.find_all('a', href=True)]

        # 爬取网站内容
        content = soup.find('div', class_='content').get_text(strip=True) if soup.find('div', class_='content') else None

        return {
            'title': title,
            'links': links,
            'content': content
        }

    except requests.exceptions.RequestException as e:
        logging.error('请求异常: %s', e)
    except Exception as e:
        logging.error('发生异常: %s', e)

    return None

def save_data(data, filename):
    # 将爬取的数据保存到文件
    with open(filename, 'w', encoding='utf-8') as file:
        file.write(f'网站标题: {data.get('title', '未找到')}
')
        file.write('网站链接:
')
        for link in data.get('links', []):
            file.write(f'{link}
')
        file.write(f'网站内容:
{data.get('content', '未找到')}')

def main():
    # 配置日志记录
    logging.basicConfig(filename='web_crawler.log', level=logging.ERROR, format='%(asctime)s - %(levelname)s - %(message)s')

    # 读取配置文件
    config = configparser.ConfigParser()
    config.read('config.ini')
    url = config.get('Website', 'URL')
    username = config.get('Login', 'Username')
    password = config.get('Login', 'Password')
    save_filename = config.get('File', 'SaveFilename')

    # 创建会话对象
    with requests.Session() as session:
        # 登录
        if login(session, url, username, password):
            # 并发爬取多个网页
            urls = [url + f'?page={i}' for i in range(1, 6)]

            with concurrent.futures.ThreadPoolExecutor() as executor:
                # 使用列表推导式,同时执行多个爬取任务
                results = [executor.submit(crawl_website, session, url) for url in urls]

            for future in concurrent.futures.as_completed(results):
                result = future.result()

                if result:
                    # 输出网站标题
                    print('网站标题:', result.get('title', '未找到'))

                    # 输出网站链接
                    print('网站链接:')
                    if result['links']:
                        for link in result['links']:
                            print(link)
                    else:
                        print('未找到网站链接')

                    # 输出网站内容
                    print('网站内容:')
                    if result['content']:
                        print(result['content'])
                    else:
                        print('未找到网站内容')

                    # 将数据保存到文件
                    save_data(result, save_filename)
                    print('数据已保存到文件')
                    print('--------------------')

        else:
            logging.error('登录失败')

if __name__ == '__main__':
    main()

使用说明

  1. 创建 config.ini 文件,配置网站地址、登录用户名和密码以及保存文件名。
  2. 运行代码,程序将根据配置信息进行登录、爬取网页和保存数据。
  3. 错误信息将记录在 web_crawler.log 文件中。

注意

  • 请勿将代码用于任何违反法律法规的行为。
  • 爬取网站时请遵守网站的robots.txt协议,避免给网站造成负担。
  • 为了保护个人隐私和安全,请不要在代码中直接写明用户名和密码,建议使用配置文件或环境变量来保存敏感信息。

进一步优化

  • 可以根据需要添加更多的错误处理,例如捕获连接超时错误等。
  • 可以使用更复杂的日志记录配置,例如设置日志级别、日志格式等。
  • 可以使用其他库,例如 requests_html 等,进一步简化代码。

希望这个改进和延伸的代码能够满足你的需求。如有其他问题,请随时提问!

Python网络爬虫:改进与扩展,实现更稳定、更安全的抓取

原文地址: http://www.cveoy.top/t/topic/nJN 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录