Python爬虫代码错误解析及优化

这段 Python 代码旨在爬取网站链接,但存在缺乏错误信息导致难以排查问题的情况。以下是对代码进行的优化和分析,并添加了更详细的错误信息输出,方便定位问题。

# -*- coding: utf-8 -*- 
import requests
from bs4 import BeautifulSoup
import urllib.parse as urlparse
import re


class UrlManager:
    def __init__(self):
        self.new_urls = set()  # 存放新的URL,将被访问并解析response里的新链接,递归下去,直到没有新的URL存进来就退出整个程序
        self.old_urls = set()  # 存在已经爬取的,且属于本站的链接

    def add_new_url(self, url):
        if url is None:
            return None
        if url not in self.new_urls and url not in self.old_urls:
            self.new_urls.add(url)

    def add_new_urls(self, urls):
        if urls is None or len(urls) == 0:
            return None
        for url in urls:
            self.add_new_url(url)

    def has_new_url(self):
        # 此处自己添加的
        if len(self.old_urls) > 10000:  # 如果经爬取的链接大于100时,退出主程序
            self.new_urls = set()
            self.old_urls = set()

        return len(self.new_urls) != 0  # 返回新URL元组是否为空,False(不为空)或True(空),空表示没有新的URL需要爬行了,会退出主程序

    def get_new_url(self):
        new_url = self.new_urls.pop()  # 从新URL元组中取一个URL
        self.old_urls.add(new_url)  # 把它移到旧的URL数组,
        return new_url


class HtmlDownLoader():
    def download(self, url):
        if url is None:
            return None
        try:
            r = requests.get(url)
            if r.status_code != 200:
                return None
            return r.text
        except Exception as e:
            print(f'下载页面 {url} 失败: {e}')
            return None


class HtmlParser:
    def __init__(self):
        self.foreign_urls = set()

    def _get_root_domain(self, url):
        # 是否应该在这里用正则判断传进来的URL是/开头,如果解析出来netloc是空,那也算是当前域名的链接
        if url is None:
            return None
        try:
            url_info = urlparse.urlparse(url)
            root_domain = url_info.netloc
            return root_domain
        except Exception as e:
            print(f'解析域名 {url} 失败: {e}')
            return None

    def _get_new_urls(self, soup, current_url):
        new_urls = set()
        links = soup.find_all('a')
        for link in links:
            new_url = link.get('href')
            if new_url is not None:
                new_url = new_url.lstrip()

            new_url_root_domain = self._get_root_domain(new_url)
            if new_url_root_domain == '':
                pass
            elif new_url_root_domain is not None:
                if self._get_root_domain(current_url) != self._get_root_domain(new_url):
                    if self._get_root_domain(new_url):
                        self.foreign_urls.add(self._get_root_domain(new_url))
                    continue
            # elif new_url_root_domain is None:
            #     pass

            new_full_url = urlparse.urljoin(current_url, new_url)
            new_urls.add(new_full_url)

        return new_urls

    def parse(self, html_content, current_url):
        if html_content is None:
            return
        try:
            soup = BeautifulSoup(html_content, 'html.parser')
            new_urls = self._get_new_urls(soup, current_url)
            return new_urls
        except Exception as e:
            print(f'解析页面 {current_url} 失败: {e}')
            return None

    def get_foreign_urls(self):
        return self.foreign_urls


class SpiderMain:
    def __init__(self, ):
        self.urls = UrlManager()
        self.html_downloader = HtmlDownLoader()
        self.parser = HtmlParser()

    def craw(self, root_url, name):
        self.urls.add_new_url(root_url)
        while self.urls.has_new_url():
            new_url = self.urls.get_new_url()
            try:
                html_content = self.html_downloader.download(new_url)
                if html_content is None:
                    continue
                new_urls = self.parser.parse(html_content, new_url)
                if new_urls is None:
                    continue
                self.urls.add_new_urls(new_urls)
                with open('%s_data.txt' % (name), 'a') as f:
                    f.write(new_url + '\n')
                print(f'爬取 {new_url} 成功')
            except Exception as e:
                print(f'爬取 {new_url} 失败: {e}')
        print(f'已爬取 {len(self.urls.old_urls)} 个链接,{self.urls.old_urls}')
        print(f'发现 {len(self.parser.foreign_urls)} 个外域链接: {self.parser.foreign_urls}')


if __name__ == '__main__':
    name = input('请输入网站名称: ')
    with open('%s.txt' % (name)) as fp:
        for u in fp:
            root_url = u.strip('\r\n')
            with open('%s_data.txt' % (name), 'a') as f:
                pass
            # root_url = u if '://' in u else 'http://' + u
            # root_url = 'http://www.zzyidc.com/'
            obj_spider = SpiderMain()
            obj_spider.craw(root_url, name)

代码优化说明

  1. 添加错误信息输出: 在 HtmlDownLoaderHtmlParserSpiderMain 中添加了 try...except 语句,捕获异常并输出错误信息,包括错误类型和发生错误的 URL。
  2. 增加判断语句: 在 SpiderMain 中增加判断语句,检查下载和解析是否成功,避免继续处理无效的数据。
  3. 简化代码: 删除了部分冗余代码,例如 _get_root_domain 中的 elif 语句。
  4. 输出更详细的信息: 在 SpiderMain 中增加了输出,包括已爬取的链接数量和发现的外域链接数量。

使用方法

  1. 将以上代码保存为 Python 文件,例如 spider.py
  2. 创建一个名为 网站名称.txt 的文本文件,将需要爬取的网站链接写入文件,每行一个链接。
  3. 运行 python spider.py 命令,输入网站名称,程序将开始爬取链接并输出爬取结果。

搜索引擎优化

  • 标题:Python爬虫代码错误解析及优化
  • 描述:本篇文章分析并优化一段 Python 爬虫代码,解决代码中缺乏错误信息导致难以排查问题的情况,并提供更详细的错误信息输出,方便定位问题。
  • 关键词:Python爬虫, 代码错误, 爬虫优化, 错误解析, 搜索引擎优化, SEO

通过以上优化,代码更易于阅读和维护,并可以更加有效地定位和解决错误。同时,文章内容也更加清晰易懂,方便读者理解和应用。*

Python爬虫代码错误解析及优化

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

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