Python爬虫案例(多线程+消息队列初阶)

目录

相关库介绍


相关库介绍

  • BeautifulSoup

  • Beautiful Soup 是一个用于从HTML或XML文件中提取数据的Python库。它提供了一种非常方便的方式来浏览文档、搜索特定标签或内容,以及对标签进行修改。Beautiful Soup的主要作用是帮助解析和提取HTML/XML文档中的数据,使得在Python中处理Web数据变得更加简单。
  • 常用方法:
    • BeautifulSoup(markup, 'html.parser'): 创建一个 BeautifulSoup 对象,用于解析 HTML 或 XML 文档。markup 是要解析的字符串或文件对象。
    • find(name, attrs, recursive, string): 查找文档中第一个符合条件的标签。
    • find_all(name, attrs, recursive, string): 查找文档中所有符合条件的标签,返回一个列表。
    • select(selector): 使用 CSS 选择器语法查找元素。
    • tag.texttag.get_text(): 获取标签内的文本内容,包括所有子孙节点的文本。
    • tag.string: 获取标签内的直系文本内容,如果有多个子节点则返回 None。
    • find_all(class_='classname'): 查找具有特定 CSS 类名的所有标签。
  • Threading

  • threading 是 Python 标准库中用于线程编程的模块。线程是一种轻量级的执行单元,允许程序并发执行多个任务。threading 模块提供了创建、管理和同步线程的工具,可以用于在多任务环境中执行并行的操作
  • 常用方法:
    • threading.Thread(target, args, kwargs): 创建一个新线程。target 参数指定线程要执行的目标函数,argskwargs 用于传递给目标函数的参数。
    • start(): 启动线程,调用线程的 run 方法。
    • join(timeout=None): 等待线程终止。如果指定了 timeout 参数,最多等待指定的秒数。
  • Requests

  •  requests 是一个用于发送 HTTP 请求的 Python 库,它简化了与 Web 服务的交互。requests 库支持多种 HTTP 方法,包括 GET、POST、PUT、DELETE 等,并提供了便捷的接口来处理请求和响应。
  • 常用方法:
    • response = requests.get('https://www.example.com')
    • response = requests.post('https://www.example.com/post-endpoint', data={'key1': 'value1', 'key2': 'value2'})
    • response = requests.get('https://www.example.com',  headers={'User-Agent': 'my-app'} ) 
    • response = requests.get('https://www.example.com', cookies={'user': 'my_user', 'token': 'my_token'})
  • Queue

  • Queue 是 Python 中的标准库 queue 模块提供的队列类,用于在多线程编程中实现线程安全的队列操作。队列是一种常见的数据结构,具有先进先出(FIFO)的特性,即先放入队列的元素将先被取出。
  • 常用方法:
    • Queue(maxsize=0)

      • 创建一个新的队列对象。maxsize 参数可用于指定队列的最大大小,如果为0则表示队列大小无限制。
    • q.put(item, block=True, timeout=None)

      • item 放入队列。如果 block 为 True(默认值),并且 timeout 为 None(默认值),则在队列未满时立即返回;如果队列已满,则阻塞直到队列有空间。如果 timeout 不为 None,则在超时之前阻塞。
    • q.get(block=True, timeout=None)

      • 从队列中取出并返回一个元素。如果 block 为 True(默认值),并且 timeout 为 None(默认值),则在队列非空时立即返回;如果队列为空,则阻塞直到队列有元素。如果 timeout 不为 None,则在超时之前阻塞。
    • q.qsize()

      • 返回队列中的元素数量。注意,由于多线程环境中,队列的大小可能在 qsize() 返回之后,但在实际操作之前发生改变,因此该方法仅提供一个近似值。
    • q.empty()

      • 如果队列为空,返回 True;否则返回 False。
    • q.full()

      • 如果队列已满,返回 True;否则返回 False。
    • q.put_nowait(item)q.get_nowait()

      • 分别是 put()get() 的非阻塞版本。它们等效于 put(item, block=False)get(block=False)
  • RE

  • re 是 Python 中的正则表达式模块,它提供了对正则表达式的支持,用于在字符串中进行模式匹配、搜索和替换等操作。正则表达式是一种强大的文本处理工具,允许你描述字符串的模式,并进行灵活的匹配和提取操作。 

  • 常用方法:

    • re.match(pattern, string, flags=0)

      • 尝试从字符串的开头匹配一个模式,如果匹配成功返回一个匹配对象,否则返回 None
    • re.search(pattern, string, flags=0)

      • 在字符串中搜索模式,返回第一个匹配对象。如果没有匹配到,返回 None
    • re.findall(pattern, string, flags=0)

      • 在字符串中查找所有匹配的子串,并以列表形式返回。每个匹配项是字符串的一部分。
    • re.finditer(pattern, string, flags=0)

      • 返回一个迭代器,生成所有匹配的匹配对象。
    • re.sub(pattern, replacement, string, count=0, flags=0)

      • 在字符串中替换匹配的模式为指定的替换字符串。可选的 count 参数指定替换的最大次数。
    • re.compile(pattern, flags=0)

      • 编译正则表达式模式,返回一个正则表达式对象。通过编译可以提高匹配效率,尤其在多次使用同一模式时。
    • re.split(pattern, string, maxsplit=0, flags=0)

      • 使用指定的模式分割字符串,返回分割后的列表。

 案例介绍

对乌云网进行爬取,爬取的内容为(支付漏洞的搜索结果),搜索支付漏洞,将搜索出来的标题和链接爬取下来。https://wy.zone.ci/searchbug.php?q=%E6%94%AF%E4%BB%98%E6%BC%8F%E6%B4%9E&page=15

 搜索支付漏洞,查询到231条记录,共16页,每条代码的规律是

<a href="bug_detail.php?wybug_id=xxx">xxx</a>

知道以上这些信息,就可以开始编写代码爬取数据了

代码实现

# 实战乌云
#引入解析和提取HTML/XML文档中的数据的库
from bs4 import BeautifulSoup
#引入线程模块
import threading
#引入请求响应HTTP获取网页信息模块
import requests
#引入消息队列模块
from queue import Queue
#引入正则表达式模块
import re

#创建一个队列,FIFO First in First Out : 先入先出
fifo = Queue()

#定义一个名为thread_body的函数/方法,并接收url,m两个参数
def thread_body(url, m):
    
    #定义一个名为visited_links的集合,用于存储不重复元素的数据结构
    visited_links = set()
    
    #自定义HTTP请求体,以键值对方式定义,User-Agent等信息可以在控制台自行查看
    header = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"}
    
    #用get方法请求url,将响应的数据赋给data
    data = requests.get(url, headers=header)
    
    #判断上面的请求是否成功,如果状态码为200则请求成功
    if data.status_code == 200:
        
        #创建实例soup,用data.text的方法获取网页的源码和数据,用BeautifulSoup解析提取
        soup = BeautifulSoup(data.text, 'html.parser')
        
        #re.compile为匹配的正则表达式,找到soup中所有a标签中属性href的值满足正则表达式的内容并赋值给data1
        data1 = soup.find_all(name='a', attrs={'href': re.compile('^bug_detail.php?')})
        
        #遍历data1中的数据
        for j in data1:
            
            #a标签中的的文字
            link_text = j.text
            
            #a标签的href属性值
            link_href = j['href']
            
            #刚才上面定义了一个visited_links集合,如果a标签的href属性值link_href不在集合中就把数据放到队列和集合中(防止数据重复)
            if link_href not in visited_links:
                
                #将数据放入队列中
                fifo.put({link_text: link_href})
                
                #将队列放入集合中
                visited_links.add(link_href)
    #如果网站访问不成功
    else:
        
        #输出请求第{m}页失败,m为函数接收的第二个参数
        print(f"请求第{m}页失败")
        
        
#定义一个空列表用来放线程
threads = []

#一共有16页,循环16次
for m in range(1, 17):
    
    #url就是上面要传入的参数,每次循环url都会改变
    url = "https://wy.zone.ci/searchbug.php?q=支付漏洞&page=%s" % m
    
    #每次循环都用threading.Thread方法启动一个线程,每个线程都去调用上面定义的thread_body函数,并把url和m传入函数
    t = threading.Thread(target=thread_body, name="线程%s" % m, args=(url, m))
    
    #启动线程
    t.start()
    
    #把线程放入刚才定义的放线程的空列表
    threads.append(t)
    
    #每启动一个线程后都输出一次线程启动
    print("线程%s启动" % m)
    
#遍历上面的线程列表
for n in threads:
    
    #用join方法实现:等每一个子线程结束了,再继续执行下面的主线程
    t.join()
    
#到这儿线程都执行结束了,如果队列不为空就输出队列中的内容
while not fifo.empty():
    #用get方法从队列取出数据
        item = fifo.get()
        print(item)






#扩展(可选),将数据存储到本地csv文件中,(思路参考,代码需要优化)
#导入csv模块
import csv


#定义一个列表放数据,data[{key1:value1},{key2:value2},{key3:valyue3}......]
data = []
#遍历获取队列数据,将数据放入列表中
for k in range(fifo.qsize()):
    item = fifo.get()
    data.append(item)
    #打开文件夹(没有会自动创建),设置字符属性等等
    with open("./spider4.csv",mode="a",encoding="utf-8",newline="") as f:
        #以字典的方式将数据写入文件
        writer=csv.DictWriter(f,fieldnames=["标题","网页"],extrasaction='ignore')
        #写入头部
        writer.writeheader()
        #多行写入
        writer.writerows(data)

结果展示 

此次案例属于python爬虫初级案例,更多实用技巧有待学习,如有错误敬请指出改正! 

  • 32
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值