【Python自动化】多线程BFS站点结构爬虫代码,支持中断恢复,带注释

简介: 【Python自动化】多线程BFS站点结构爬虫代码,支持中断恢复,带注释
from collections import deque
from urllib.parse import urljoin, urlparse
import requests
from pyquery import PyQuery as pq
import re
from EpubCrawler.util import request_retry
import traceback
from functools import reduce
from concurrent.futures import ThreadPoolExecutor
# 子线程入口,包装`get_next`并添加异常处理和结果传递
def tr_get_next_safe(i, url, res, args):
    try:
        print(url)
        ns = get_next(url, args)
        res[i] = ns
    except:
        traceback.print_exc()
def get_next(url, args):
    # 请求该网页
    # 这里是带重试的 GET
    # 可以看我其它项目源码,也可以自己写一个。
    html = request_retry(
        'GET', url, 
        retry=args.retry,
        proxies=args.proxy,
    ).text
    if not html: return []
    # 解析其中所有链接的`href`属性
    rt = pq(html)
    el_links = rt('a')
    links = [
        urljoin(url, pq(el).attr('href').strip()) 
        for el in el_links
        if pq(el).attr('href')
    ]
    # 过滤掉其它网站的链接
    hostname = urlparse(url).hostname
    links = [
        l for l in links 
        if urlparse(l).hostname == hostname
    ]
    # print(f'url: {url}\nnext: {links}\n')
    return links
def whole_site(args):
    # `args.site`:`str`,站点网址
    # `args.proxy`:`str`,代理地址,默认`None`
    # `args.retry`:`int`,重试次数
    # `args.threads`:`int`,线程数
    site = args.site
    if args.proxy: 
        args.proxy = {'http': args.proxy, 'https': args.proxy}
    pref = re.sub(r'[^\w\-\.]', '-', site)
    # 结果保存文件和历史记录文件
    res_fname = f'{pref}.txt'
    rec_fname = f'{pref}_rec.txt'
    ofile = open(res_fname, 'a', encoding='utf8')
    rec_file = open(rec_fname, 'a+', encoding='utf8')
    # 判断记录文件是否有记录
    if rec_file.tell() != 0:
        # 读取所有行,过滤空行
        rec_file.seek(0, 0)
        rec = rec_file.read().split('\n')
        rec = [l for l in rec if l.strip()]
        # -1 的数量是弹出操作的数量,从队列前方移除指定数量的条目
        pop_count = rec.count('-1')
        q = deque([l for l in rec if l != "-1"][pop_count:])
        vis = set(rec)
    else:
        # 初始化队列和已访问集
        q = deque([site])
        vis = set([site])
        rec_file.write(site + '\n')
    pool = ThreadPoolExecutor(args.threads)
    while q:
        # 取出指定数量的链接
        pop_cnt = min(len(q), args.threads)
        urls = [q.popleft() for _ in range(pop_cnt)]
        # 调用子线程获取引用
        nexts = [[] for _ in range(pop_cnt)]
        hdls = []
        for i, url in enumerate(urls):
            h = pool.submit(tr_get_next_safe, i, url, nexts, args)
            hdls.append(h)
        for h in hdls: h.result()
        # 过滤空项、合并、去重
        nexts = [n for n in nexts if n]
        nexts = set(reduce(lambda x, y: x + y, nexts, []))
        # 这里可以过滤常见文件后缀,比如 PDF、DOC 等等
        # nexts = (u for u in nexts if not u.endswith('.xml'))
        # 将本次迭代结果更新到磁盘
        # -1 表示弹出元素
        for url in urls:
            ofile.write(url + '\n')
            rec_file.write('-1\n')
        # 将没有访问的引用标记访问,并更新到队列
        for n in nexts:
            if n not in vis:
                vis.add(n)
                q.append(n)
                rec_file.write(n + '\n')
    ofile.close()
    rec_file.close()
相关文章
Python GIL(全局解释器锁)机制对多线程性能影响的深度分析
在Python开发中,GIL(全局解释器锁)一直备受关注。本文基于CPython解释器,探讨GIL的技术本质及其对程序性能的影响。GIL确保同一时刻只有一个线程执行代码,以保护内存管理的安全性,但也限制了多线程并行计算的效率。文章分析了GIL的必要性、局限性,并介绍了多进程、异步编程等替代方案。尽管Python 3.13计划移除GIL,但该特性至少要到2028年才会默认禁用,因此理解GIL仍至关重要。
102 16
Python GIL(全局解释器锁)机制对多线程性能影响的深度分析
|
7天前
|
python3多线程中使用线程睡眠
本文详细介绍了Python3多线程编程中使用线程睡眠的基本方法和应用场景。通过 `time.sleep()`函数,可以使线程暂停执行一段指定的时间,从而控制线程的执行节奏。通过实际示例演示了如何在多线程中使用线程睡眠来实现计数器和下载器功能。希望本文能帮助您更好地理解和应用Python多线程编程,提高程序的并发能力和执行效率。
35 20
|
25天前
|
Python高性能编程:五种核心优化技术的原理与Python代码
Python在高性能应用场景中常因执行速度不及C、C++等编译型语言而受质疑,但通过合理利用标准库的优化特性,如`__slots__`机制、列表推导式、`@lru_cache`装饰器和生成器等,可以显著提升代码效率。本文详细介绍了这些实用的性能优化技术,帮助开发者在不牺牲代码质量的前提下提高程序性能。实验数据表明,这些优化方法能在内存使用和计算效率方面带来显著改进,适用于大规模数据处理、递归计算等场景。
59 5
Python高性能编程:五种核心优化技术的原理与Python代码
|
2月前
|
课程设计项目之基于Python实现围棋游戏代码
游戏进去默认为九路玩法,当然也可以选择十三路或是十九路玩法 使用pycharam打开项目,pip安装模块并引用,然后运行即可, 代码每行都有详细的注释,可以做课程设计或者毕业设计项目参考
78 33
【Azure Developer】Python代码调用Graph API将外部用户添加到组,结果无效,也无错误信息
根据Graph API文档,在单个请求中将多个成员添加到组时,Python代码示例中的`members@odata.bind`被错误写为`members@odata_bind`,导致用户未成功添加。
54 10
Python网络爬虫:Scrapy框架的实战应用与技巧分享
【10月更文挑战第27天】本文介绍了Python网络爬虫Scrapy框架的实战应用与技巧。首先讲解了如何创建Scrapy项目、定义爬虫、处理JSON响应、设置User-Agent和代理,以及存储爬取的数据。通过具体示例,帮助读者掌握Scrapy的核心功能和使用方法,提升数据采集效率。
194 6
Python网络爬虫:Scrapy框架的实战应用与技巧分享
【10月更文挑战第26天】Python是一种强大的编程语言,在数据抓取和网络爬虫领域应用广泛。Scrapy作为高效灵活的爬虫框架,为开发者提供了强大的工具集。本文通过实战案例,详细解析Scrapy框架的应用与技巧,并附上示例代码。文章介绍了Scrapy的基本概念、创建项目、编写简单爬虫、高级特性和技巧等内容。
155 4
Python进行网络爬虫:Scrapy框架的实践
【8月更文挑战第17天】网络爬虫是自动化程序,用于从互联网收集信息。Python凭借其丰富的库和框架成为构建爬虫的首选语言。Scrapy作为一款流行的开源框架,简化了爬虫开发过程。本文介绍如何使用Python和Scrapy构建简单爬虫:首先安装Scrapy,接着创建新项目并定义爬虫,指定起始URL和解析逻辑。运行爬虫可将数据保存为JSON文件或存储到数据库。此外,Scrapy支持高级功能如中间件定制、分布式爬取、动态页面渲染等。在实践中需遵循最佳规范,如尊重robots.txt协议、合理设置爬取速度等。通过本文,读者将掌握Scrapy基础并了解如何高效地进行网络数据采集。
310 6
Python爬虫开发:BeautifulSoup、Scrapy入门
在现代网络开发中,网络爬虫是一个非常重要的工具。它可以自动化地从网页中提取数据,并且可以用于各种用途,如数据收集、信息聚合和内容监控等。在Python中,有多个库可以用于爬虫开发,其中BeautifulSoup和Scrapy是两个非常流行的选择。本篇文章将详细介绍这两个库,并提供一个综合详细的例子,展示如何使用它们来进行网页数据爬取。
Python高效爬虫——scrapy介绍与使用
Scrapy是一个快速且高效的网页抓取框架,用于抓取网站并从中提取结构化数据。它可用于多种用途,从数据挖掘到监控和自动化测试。 相比于自己通过requests等模块开发爬虫,scrapy能极大的提高开发效率,包括且不限于以下原因: 1. 它是一个异步框架,并且能通过配置调节并发量,还可以针对域名或ip进行精准控制 2. 内置了xpath等提取器,方便提取结构化数据 3. 有爬虫中间件和下载中间件,可以轻松地添加、修改或删除请求和响应的处理逻辑,从而增强了框架的可扩展性 4. 通过管道方式存储数据,更加方便快捷的开发各种数据储存方式

热门文章

最新文章