爬虫实战--爬取简单文字图片并保存到mongodb数据库

news2024/11/18 19:41:43

文章目录

  • 前言
  • 发现宝藏

前言

为了巩固所学的知识,作者尝试着开始发布一些学习笔记类的博客,方便日后回顾。当然,如果能帮到一些萌新进行新技术的学习那也是极好的。作者菜菜一枚,文章中如果有记录错误,欢迎读者朋友们批评指正。
(博客的参考源码可以在我主页的资源里找到,如果在学习的过程中有什么疑问欢迎大家在评论区向我提出)

发现宝藏

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。【宝藏入口】。

http://jhsjk.people.cn/testnew/result

import os
import re
from datetime import datetime
import requests
import json
from bs4 import BeautifulSoup
from pymongo import MongoClient
from tqdm import tqdm

class ArticleCrawler:
    def __init__(self, catalogues_url, card_root_url, output_dir, db_name='ren-ming-wang'):
        self.catalogues_url = catalogues_url
        self.card_root_url = card_root_url
        self.output_dir = output_dir
        self.client = MongoClient('mongodb://localhost:27017/')
        self.db = self.client[db_name]
        self.catalogues = self.db['catalogues']
        self.cards = self.db['cards']
        self.headers = {
            'Referer': 'https://jhsjk.people.cn/result?',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                          'Chrome/119.0.0.0 Safari/537.36',
            'Cookie': '替换成你自己的',
        }

    # 发送带参数的get请求并获取页面内容
    def fetch_page(self, url, page):
        params = {
            'keywords': '',
            'isFuzzy': '0',
            'searchArea': '0',
            'year': '0',
            'form': '',
            'type': '0',
            'page': page,
            'origin': '全部',
            'source': '2',
        }
        response = requests.get(url, params=params, headers=self.headers)
        soup = BeautifulSoup(response.text, 'html.parser')
        return soup

    # 解析请求版面
    def parse_catalogues(self, json_catalogues):
        card_list = json_catalogues['list']
        for list in card_list:
            a_tag = 'article/'+list['article_id']
            card_url = self.card_root_url + a_tag
            card_title = list['title']
            updateTime = list['input_date']
            self.parse_cards(card_url, updateTime)
            date = datetime.now()
            catalogues_id = list['article_id']+'01'

            # 检查重复标题
            existing_docs = self.catalogues.find_one({'id': catalogues_id})
            if existing_docs is not None:
                print(f'版面id: {catalogues_id}【已经存在】')
                continue

            card_data = {
                'id': catalogues_id,
                'title': card_title,
                'page': 1,
                'serial': 1,
                # 一个版面一个文章
                'dailyId': '',
                'cardSize': 1,
                'subjectCode': '50',
                'updateTime': updateTime,
                'institutionnCode': '10000',
                'date': date,
                'snapshot': {

                }
            }
            self.catalogues.insert_one(card_data)
            print(f'版面id: {catalogues_id}【插入成功】')

    # 解析请求文章
    def parse_cards(self, url, updateTime):
        response = requests.get(url, headers=self.headers)
        soup = BeautifulSoup(response.text, "html.parser")
        try:
            title = soup.find("div", "d2txt clearfix").find('h1').text
        except:
            try:
                title = soup.find('h1').text
            except:
                print(f'【无法解析该文章标题】{url}')
        html_content = soup.find('div', 'd2txt_con clearfix')
        text = html_content.get_text()
        imgs = [img.get('src') or img.get('data-src') for img in html_content.find_all('img')]
        cleaned_content = self.clean_content(text)
        # 假设我们有一个正则表达式匹配对象match
        match = re.search(r'\d+', url)
        # 获取匹配的字符串
        card_id = match.group()
        date = datetime.now()
        if len(imgs) != 0:
            # 下载图片
            self.download_images(imgs, card_id)

        # 创建文档
        document = {
            'id': card_id,
            'serial': 1,
            'page': 1,
            'url' : url,
            'type': 'ren-ming-wang',
            'catalogueId': card_id + '01',
            'subjectCode': '50',
            'institutionCode': '10000',
            'updateTime': updateTime,
            'flag': 'true',
            'date': date,
            'title': title,
            'illustrations': imgs,
            'html_content': str(html_content),
            'content': cleaned_content
        }
        # 检查重复标题
        existing_docs = self.cards.find_one({'id': card_id})
        if existing_docs is None:
            # 插入文档
            self.cards.insert_one(document)
            print(f"文章id:{card_id}【插入成功】")
        else:
            print(f"文章id:{card_id}【已经存在】")

    # 文章数据清洗
    def clean_content(self, content):
        if content is not None:
            content = re.sub(r'\r', r'\n', content)
            content = re.sub(r'\n{2,}', '', content)
            # content = re.sub(r'\n', '', content)
            content = re.sub(r' {6,}', '', content)
            content = re.sub(r' {3,}\n', '', content)
            content = content.replace('<P>', '').replace('<\P>', '').replace('&nbsp;', ' ')
        return content

    # 下载图片
    def download_images(self, img_urls, card_id):
        # 根据card_id创建一个新的子目录
        images_dir = os.path.join(self.output_dir, card_id)
        if not os.path.exists(images_dir):
            os.makedirs(images_dir)
            downloaded_images = []
            for img_url in img_urls:
                try:
                    response = requests.get(img_url, stream=True)
                    if response.status_code == 200:
                        # 从URL中提取图片文件名
                        image_name = os.path.join(images_dir, img_url.split('/')[-1])
                        # 确保文件名不重复
                        if os.path.exists(image_name):
                            continue
                        with open(image_name, 'wb') as f:
                            f.write(response.content)
                        downloaded_images.append(image_name)
                        print(f"Image downloaded: {img_url}")
                except Exception as e:
                    print(f"Failed to download image {img_url}. Error: {e}")
            return downloaded_images
        # 如果文件夹存在则跳过
        else:
            print(f'文章id为{card_id}的图片文件夹已经存在')

    # 查找共有多少页
    def find_page_all(self, soup):
        # 查找<em>标签
        em_tag = soup.find('em', onclick=True)
        # 从onclick属性中提取页码
        if em_tag and 'onclick' in em_tag.attrs:
            onclick_value = em_tag['onclick']
            page_number = int(onclick_value.split('(')[1].split(')')[0])
            return page_number
        else:
            print('找不到总共有多少页数据')

    # 关闭与MongoDB的连接
    def close_connection(self):
        self.client.close()

    # 执行爬虫,循环获取多页版面及文章并存储
    def run(self):
        soup_catalogue = self.fetch_page(self.catalogues_url, 1)
        page_all = self.find_page_all(soup_catalogue)
        if page_all:
            for index in tqdm(range(1, page_all), desc='Page'):
            # for index in tqdm(range(1, 50), desc='Page'):
                soup_catalogues = self.fetch_page(self.catalogues_url, index).text
                # 解析JSON数据
                soup_catalogues_json = json.loads(soup_catalogues)
                self.parse_catalogues(soup_catalogues_json)
                print(f'======================================Finished page {index}======================================')

        self.close_connection()

if __name__ == "__main__":
    crawler = ArticleCrawler(
        catalogues_url='http://jhsjk.people.cn/testnew/result',
        card_root_url='http://jhsjk.people.cn/',
        output_dir='D:\\ren-ming-wang\\img'
    )
    crawler.run()  # 运行爬虫,搜索所有内容
    crawler.close_connection()  # 关闭数据库连接

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1435170.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

七、类与对象

文章目录 类与对象1.1 自定义类1.2 第一个类1.3 private变量1.4 变量默认值1.5 构造方法1.6 类和对象的生命周期 类与对象 本文为书籍《Java编程的逻辑》1和《剑指Java&#xff1a;核心原理与应用实践》2阅读笔记 将客观世界中存在的一切可以描述的事物称为对象&#xff08;实…

浏览器提示ERR_SSL_KEY_USAGE_INCOMPATIBLE解决

ERR_SSL_KEY_USAGE_INCOMPATIBLE报错原因 ERR_SSL_KEY_USAGE_INCOMPATIBLE 错误通常发生在使用 SSL/TLS 连接时,指的是客户端和服务器之间进行安全通信尝试失败,原因是证书中的密钥用途(Key Usage)或扩展密钥用途(Extended Key Usage, EKU)与正在尝试的操作不兼容。这意味…

性能评测|虚拟化和裸金属 K8s 哪个性能更好?

本文重点 整体而言&#xff0c;SKS&#xff08;虚拟机 Kubernetes&#xff09;可以达到裸金属 Kubernetes 性能的 82% – 96%&#xff0c;满足绝大部分场景下生产容器应用的性能需求。更多虚拟化与裸金属 Kubernetes 架构、特性、适用场景与性能对比&#xff0c;欢迎阅读文末电…

【算法】枚举——蓝桥杯、日期统计、特殊日期(位数之和)、2023、特殊日期(倍数)、跑步锻炼

文章目录 蓝桥杯日期统计特殊日期&#xff08;位数之和&#xff09;2023特殊日期&#xff08;倍数&#xff09;跑步锻炼 蓝桥杯 日期统计 日期统计 如果暴力枚举100个数的八次循环那就是1016次运算&#xff0c;时间复杂度太高了&#xff0c;好在前四次的2023是确定的&#xf…

Mybatis中的sql-xml延迟加载机制

Mybatis中的sql-xml延迟加载机制 hi&#xff0c;我是阿昌&#xff0c;今天记录一下关于Mybatis中的sql-xml延迟加载机制 一、前言 首先mybatis技术本身就不多介绍&#xff0c;说延迟加载机制之前&#xff0c;那要先知道2个概念&#xff1a; 主查询对象关联对象 假设咱们现…

人工智能福利站,初识人工智能,图神经网络学习,第二课

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

UML之在Markdown中使用Mermaid绘制类图

1.UML概述 UML&#xff08;Unified modeling language UML&#xff09;统一建模语言&#xff0c;是一种用于软件系统分析和设计的语言工具&#xff0c;它用于帮助软件开发人员进行思考和记录思路。 类图是描述类与类之间的关系的&#xff0c;是UML图中最核心的。类图的是用于…

SpringBoot实战第三天

今天主要完成了&#xff1a; 新增棋子分类 棋子分类列表 获取棋子分类详情 更新棋子分类 更新棋子分类和添加棋子分类_分组校验 新增棋子 新增棋子参数校验 棋子分类列表查询(条件分页) 先给出分类实体类 Data public class Category {private Integer id;//主键IDNot…

mysql 批量查询取每一组最新一条数据

AI回答 需求 根据车牌号查询最新的一条交车记录的‘合同号’ &#xff0c;与上面需要类似&#xff0c;这里只需要查询‘合同号’这个字段 方式1 直接把需要查询的字段加上contract_no&#xff0c;直接查&#xff0c;不用子查询 SELECT number_plate,id,contract_no, MAX( …

❤ React18 环境搭建项目与运行(地址已经放Gitee开源)

❤ React项目搭建与运行 环境介绍 node v20.11.0 react 18.2 react-dom 18.2.0一、React环境搭建 第一种普通cra搭建 1、检查本地环境 node版本 18.17.0 检查node和npm环境 node -v npm -v 2、安装yarn npm install -g yarn yarn --version 3、创建一个新的React项目…

SSRF漏洞给云服务元数据带来的安全威胁

文章目录 前言元数据服务威胁1.1 Metadata元数据1.2 RAM资源管理角色1.3 STS 临时凭据利用1.4 CF云环境利用框架1.5 元数据安全性增强 TerraformGoat2.1 永久性AccessKey2.2 SSRF靶场环境搭建2.3 腾讯云CVM配角色2.4 接管腾讯云控制台 SSRF组合拳案例3.1 上传图片功能SSRF3.2 文…

vue3-内置组件-Transition

基于状态变化的过渡和动画&#xff08;常用&#xff09; 建议多看几遍~~。然后动手去写写&#xff0c;学编程只有多动手才能有感觉。 内置组件: 它在任意别的组件中都可以被使用&#xff0c;无需注册。 Vue 提供了两个内置组件&#xff0c;可以帮助你制作基于状态变化的过渡和动…

Jmeter 01 -概述线程组

1、Jmeter:概述 1.1 是什么&#xff1f; Jmeter是Apache公司使用Java 开发的一款测试工具 1.2 为什么&#xff1f; 高效、功能强大 模拟一些高并发或多次循环等特殊场景 1.3 怎么用&#xff1f; 下载安装 1、下载jmeter&#xff0c;解压缩2、安装Java环境&#xff08;jmet…

【保姆级教程|YOLOv8改进】【5】精度与速度双提升,使用FasterNet替换主干网络

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

为什么(如何)从 Java 8/11 迁移到 Java 21,从 Spring Boot 2 迁移到最新的 Spring Boot 3.2 ?

介绍 如果您的工作配置与 Java 有一定的关系&#xff0c;您一定已经注意到 了Java 最新稳定版本 Java 21 引起了很多关注。 这个新版本引入了一些未来的功能&#xff0c;改进了之前引入/孵化的一些突破性功能&#xff0c;弃用了多余的功能&#xff0c;并删除了一些错误。它使…

Halcon 缺陷检测

文章目录 开闭运算&#xff0c;腐蚀膨胀的亮点问题灰度图像的开闭运算&#xff0c;腐蚀膨胀的亮点问题算子二值化算子 Halcon blob特征处理的方法检测缺陷Halcon Blob特征差分的方法检测缺陷Halcon 极坐标变换&#xff08;环形先转换坐标&#xff09;blob特征Halcon Blob局部二…

PySpark(四)PySpark SQL、Catalyst优化器、Spark SQL的执行流程

目录 PySpark SQL 基础 SparkSession对象 DataFrame入门 DataFrame构建 DataFrame代码风格 DSL SQL SparkSQL Shuffle 分区数目 DataFrame数据写出 Spark UDF Catalyst优化器 Spark SQL的执行流程 PySpark SQL 基础 PySpark SQL与Hive的异同 Hive和Spark 均是:“分…

2月5日作业

1.请编程实现哈希表的创建存储数组(12,24,234,234,23,234,23),输入key查找的值&#xff0c;实现查找功能 #include<stdio.h> #include<string.h> #include<stdlib.h> #include<math.h> typedef int datatype; typedef struct node {datatype data;str…

JenkinsGitLab完成自动化构建部署

关于GitLab安装:GitLab安装-CSDN博客 Docker中安装GitLab:Docker下安装GitLab-CSDN博客 安装JenKins Jenkins官网:Jenkins 中文版:Jenkins 安装时候中文页面的war包下不来 在英文页面 记得装JDK8以上 JenKins使用java写的 运行JenKins需要JDK环境 我这里已经装好了 将下…

VXLAN:虚拟化网络的强大引擎

1.什么是VXLAN VXLAN&#xff08;Virtual eXtensible Local Area Network&#xff0c;虚拟扩展局域网&#xff09;&#xff0c;是由IETF定义的NVO3&#xff08;Network Virtualization over Layer 3&#xff09;标准技术之一&#xff0c;是对传统VLAN协议的一种扩展。VXLAN的特…