闲来无事,写个脚本爬一下快递信息

  1. 多线程爬取:可以使用Python中的多线程或异步IO技术来加速爬取速度,提高效率。
  2. 自动识别快递公司:可以通过输入的快递单号自动识别快递公司,然后根据不同公司的网站结构来爬取相应的信息。
  3. 数据存储:可以将爬取的数据存储到数据库或者文件中,方便后续的分析和使用。
  4. 可视化展示:可以使用Python中的数据可视化库,将爬取的数据可视化展示出来,方便用户查看和分析。
  5. 自动重试:可以在网络连接不稳定或者请求失败时自动重试,提高爬取成功率。
  6. 验证码识别:当出现验证码时,可以使用Python中的验证码识别库,自动识别验证码并输入,避免手动输入验证码的麻烦。
import requests
from bs4 import BeautifulSoup
import threading
import time
import random
import os
import re
import json
from PIL import Image
import pytesseract
import pymongo
import matplotlib.pyplot as plt

# 定义线程数和线程锁
thread_num = 10
lock = threading.Lock()

# 定义快递公司列表和快递公司匹配正则表达式
express_companies = {
    "shunfeng": {
        "name": "顺丰速运",
        "regex": "^SF\d{12}$"
    },
    "yuantong": {
        "name": "圆通速递",
        "regex": "^[A-Za-z0-9]{12}$"
    },
    "zhongtong": {
        "name": "中通快递",
        "regex": "^[A-Za-z0-9]{12}$"
    },
    "yunda": {
        "name": "韵达快递",
        "regex": "^120\d{11}$"
    }
}

# 定义MongoDB客户端
client = pymongo.MongoClient("mongodb://localhost:27017/")
db = client["express"]
collection = db["tracking_info"]

# 定义请求头
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36"
}

# 定义验证码识别函数
def recognize_captcha(captcha_path):
    image = Image.open(captcha_path)
    captcha = pytesseract.image_to_string(image)
    captcha = re.sub(r"\W", "", captcha)
    return captcha

# 定义爬取函数
def crawl(tracking_number):
    # 自动识别快递公司
    company = None
    for key, value in express_companies.items():
        if re.match(value["regex"], tracking_number):
            company = key
            break
    if not company:
        print(f"未知快递公司,快递单号为:{tracking_number}")
        return
    print(f"开始爬取 {express_companies[company]['name']} 的快递信息,快递单号为:{tracking_number}")

    # 发送请求
    url = f"https://www.sf-express.com/sf-service-web/service/bills/{tracking_number}"
    response = requests.get(url, headers=headers)

    # 验证码识别
    if "验证码" in response.text:
        print(f"需要输入验证码,快递单号为:{tracking_number}")
        # 提取验证码图片链接
        soup = BeautifulSoup(response.text, "html.parser")
        captcha_url = soup.select_one(".captcha img")["src"]
        captcha_path = f"./captcha/{tracking_number}.png"
        # 下载验证码图片
        response = requests.get(captcha_url, headers=headers)
        with open(captcha_path, "wb") as f:
            f.write(response.content)
        # 识别验证码
        captcha = recognize_captcha(captcha_path)
        # 删除验证码图片
        os.remove(captcha_path)
        # 构造请求参数
        data = {
            "captcha": captcha,
            "billNo": tracking_number
        }
        response = requests.post(url, headers=headers, data=data)

    # 解析网页内容并保存到MongoDB
    soup = BeautifulSoup(response.text, "html.parser")
    status_list = soup.select(".status-list li")
    tracking_info = []
    for status in status_list:
        date = status.select_one(".date").text.strip()
        time = status.select_one(".time").text.strip()
        location = status.select_one(".location").text.strip()
        status_desc = status.select_one(".status-desc").text.strip()
        tracking_info.append({
            "date": date,
            "time": time,
            "location": location,
            "status_desc": status_desc
        })
    data = {
        "tracking_number": tracking_number,
        "company": express_companies[company]["name"],
        "tracking_info": tracking_info
    }
    collection.insert_one(data)
    print(f"{tracking_number} 的快递信息已保存到MongoDB")

    # 可视化展示
    dates = [info["date"] for info in tracking_info]
    times = [info["time"] for info in tracking_info]
    status_descs = [info["status_desc"] for info in tracking_info]

    plt.plot(dates, status_descs)
    plt.title(f"{express_companies[company]['name']} 快递单号:{tracking_number}")
    plt.xlabel("日期")
    plt.ylabel("快递状态")
    plt.xticks(rotation=45)
    plt.show()

# 定义线程函数
def thread_func(tracking_numbers):
    for tracking_number in tracking_numbers:
        crawl(tracking_number)
        time.sleep(random.randint(1, 3))

# 主函数
if __name__ == "__main__":
    # 读取快递单号
    with open("tracking_numbers.txt", "r") as f:
        tracking_numbers = f.read().splitlines()

    # 分配任务给线程
    threads = []
    for i in range(thread_num):
        start = i * len(tracking_numbers) // thread_num
        end = (i + 1) * len(tracking_numbers) // thread_num
        thread = threading.Thread(target=thread_func, args=(tracking_numbers[start:end],))
        threads.append(thread)

    # 启动线程
    for thread in threads:
        thread.start()

    # 等待线程结束
    for thread in threads:
        thread.join()

    # 输出爬取结果
    print("爬取完成")

这个代码实现了:

  1. 多线程爬取:通过定义线程数和线程锁来实现多线程爬取,加速爬取速度。

  2. 自动识别快递公司:通过定义快递公司列表和快递公司匹配的正则表达式来实现自动识别快递公司。

  3. 数据存储:通过连接MongoDB数据库,并定义数据结构,将爬取的快递信息保存到MongoDB中。

  4. 可视化展示:通过使用matplotlib库,将爬取的快递信息进行数据可视化展示。

  5. 自动重试:虽然没有在代码中体现,但是可以加入重试机制,当网络连接不稳定或者请求失败时自动重试。

  6. 验证码识别:当出现验证码时,通过下载验证码图片,使用pytesseract库进行验证码识别,自动输入验证码。

需要注意的是,这个示例代码只是一个简单的爬虫示例,实际的爬虫任务可能更加复杂。在实际的爬虫开发中,需要根据具体的场景和需求来选择使用哪些技术和工具来完成爬虫任务。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JF Coder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值