Python 网站爬虫代码优化与扩展: 超时设置、并发爬取、错误处理

在之前的版本中,我们已经实现了一个基本的网站爬虫,可以获取网页标题、链接和内容。为了让爬虫更加稳定、高效,我们需要对代码进行优化和扩展。

在这个版本中,根据之前的建议,我们进行了如下改进和扩展:

  1. 添加了爬取任务的超时时间配置,并通过configparser模块从配置文件中读取配置。
  2. crawl_website函数中,优化了异常处理逻辑,使用requests.exceptions.RequestException来捕获请求异常,并记录错误日志。
  3. save_data函数中,对数据进行格式化输出,使保存的文件更易读。
  4. 在循环中添加了延迟,以降低对目标网站的访问频率。

以下是优化后的代码:

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

def login(session, url, username, password):
    try:
        response = session.get(url, timeout=5)
        response.raise_for_status()
        soup = BeautifulSoup(response.content, 'html.parser')
        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.update({'username': username, 'password': password})
        response = session.post(url + action, data=form_data, timeout=5)
        response.raise_for_status()
        if '登录失败' in response.text:
            logging.error('登录失败')
            return False
        return True
    except requests.exceptions.RequestException as e:
        logging.error('请求异常: %s', e)
    except Exception as e:
        logging.error('发生异常: %s', e)
    return False

def crawl_website(session, url):
    try:
        response = session.get(url, timeout=5)
        response.raise_for_status()
        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 {
            'url': url,
            '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['url']} 的标题: {data.get('title', '未找到')}
')
        file.write('网站链接:
')
        for link in data.get('links', []):
            file.write(f'{link}
')
        file.write(f'网站 {data['url']} 的内容:
{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')

    # 定义爬取任务的超时时间
    timeout = int(config.get('Crawler', 'Timeout', fallback='5'))

    # 创建会话对象
    with requests.Session() as session:
        if login(session, url, username, password):
            urls = [url + f'?page={i}' for i in range(1, 6)]

            # 使用concurrent.futures.ThreadPoolExecutor进行并发爬取
            with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
                futures = [executor.submit(crawl_website, session, url) for url in urls]

            for future, url in zip(concurrent.futures.as_completed(futures), urls):
                result = future.result()
                if result:
                    print(f'网站 {result['url']} 的标题:', result.get('title', '未找到'))
                    print(f'网站 {result['url']} 的链接:')
                    if result['links']:
                        for link in result['links']:
                            print(link)
                    else:
                        print('未找到网站链接')
                    print(f'网站 {result['url']} 的内容:')
                    if result['content']:
                        print(result['content'])
                    else:
                        print('未找到网站内容')
                    save_data(result, f'{save_filename}_{result['url']}')
                    print(f'数据已保存到文件 {save_filename}_{result['url']}')
                    print('--------------------')
                    time.sleep(1)  # 添加延迟,避免对目标网站造成过大压力
        else:
            logging.error('登录失败')

if __name__ == '__main__':
    main()

根据需求,你可以进一步完善代码、添加更多的错误处理、优化日志记录等。

希望这些建议能帮助你继续完善和延伸代码!如果你有其他问题,请随时提问。

Python 网站爬虫代码优化与扩展: 超时设置、并发爬取、错误处理

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

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