爬虫实战--人民网

news2024/11/17 9:39:02

文章目录

  • 前言
  • 发现宝藏

前言

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

发现宝藏

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

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/1435656.html

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

相关文章

【C语言不能不会的操作】调试-万字详解【windows操作系统下】(会写bug还会调试解决bug的程序员简直帅呆了,赶紧点赞收藏)

目录 1. 什么是bug&#xff1f; 2. 调试是什么&#xff1f;有多重要&#xff1f; 2.1调试是什么 2.2 调试的基本步骤 2.3 Debug和Release的介绍 3. Windows环境调试介绍 3.1 调试环境的准备 3.2 学会快捷键 ​编辑 3.3更多的快捷键 3.4 调试的时候查看程序当前信息…

【lesson41】理解文件系统(2)

文章目录 理解文件系统 理解文件系统 我们之前学过&#xff0c;一个文件可以有多个datablock块&#xff0c;但是如果这个文件太大了怎么办&#xff1f;datablock中&#xff0c;不是所有的datablock只能存文件数据&#xff0c;也可以存其它块的块号。 inode Vs 文件名 找到文件…

MySQL数据库③_MySQL数据类型和测试

目录 1. MySQL数据类型分类 1.1 类型汇总 1.2 整数类型 1.3 浮点数类型和定点数类型 1.4 字符串类型和文本类型 1.5 日期与时间类型 1.6 二进制类型 2. 有代表的类型测试 2.1 tinyint类型 2.2 bit类型 2.3 float类型 2.4 decimal类型 2.5 char和varchar类型 2.6 …

Vue3快速上手(一)使用vite创建项目

一、准备 在此之前&#xff0c;你的电脑&#xff0c;需要安装node.js,我这边v18.19.0 wangdymb 2024code % node -v v18.19.0二、创建 执行npm create vuelatest命令即可使用vite创建vue3项目 有的同学可能卡主不动&#xff0c;可能是npm的registry设置的问题 先看下&#x…

为后端做准备

这里写目录标题 flask 文件上传与接收flask应答&#xff08;接收请求&#xff08;文件、数据&#xff09;flask请求&#xff08;上传文件&#xff09;传递参数和文件 argparse 不从命令行调用参数1、设置default值2、"从命令行传入的参数".split()3、[--input,内容] …

备战蓝桥杯---数据结构与STL应用(进阶2)

本文将主要围绕有关map的今典应用展开&#xff1a; 下面我用图进行分析&#xff1a; 下面为AC代码&#xff1a; #include<bits/stdc.h> using namespace std; struct Point {int x,y;bool operator < (const Point & r) const {return x < r.x || ( x r.x &a…

【Java八股面试系列】JVM-垃圾回收

目录 垃圾回收 堆空间的基本结构 内存分配和回收原则 分代收集机制 Minor GC 流程 空间分配担保 老年代 大对象直接进入老年代 长期存活的对象将进入老年代 GC的区域 对象存活判定算法 引用计数法 可达性分析算法 finalize() 字符串常量判活 类判活 垃圾回收算…

智能优化算法 | Matlab实现合作优化算法(CSA)(内含完整源码)

文章目录 效果一览文章概述源码设计参考资料效果一览 文章概述 智能优化算法 | Matlab实现合作优化算法(CSA)(内含完整源码) 源码设计 clear clc close SearchAgents_no=30; % Number of search agents Max_iteration=1000;

宠物空气净化器哪个品牌质量好?实惠的猫用猫用净化器牌子测评

作为宠物主人&#xff0c;我们深知养宠物的乐趣和责任&#xff0c;但同时也面临着一些挑战&#xff0c;比如宠物脱毛、气味和室内空气质量等问题。正因如此&#xff0c;越来越多的家庭选择宠物空气净化器&#xff0c;为我们营造一个清新、健康的居住环境。 无论我们多么喜欢我…

新零售的升维体验,摸索华为云GaussDB如何实现数据赋能

新零售商业模式 商业模式通常是由客户价值、企业资源和能力、盈利方式三个方面构成。其最主要的用途是为实现客户价值最大化。 商业模式通过把能使企业运行的内外各要素整合起来&#xff0c;从而形成一个完整的、高效率的、具有独特核心竞争力的运行系统&#xff0c;并通过最…

防范恶意勒索攻击!亚信安全发布《勒索家族和勒索事件监控报告》

本周态势快速感知 本周全球共监测到勒索事件81起&#xff0c;事件数量有所下降&#xff0c;比上月降低20%。 lockbit3.0仍然是影响最严重的勒索家族&#xff1b;akira和incransom也是两个活动频繁的恶意家族&#xff0c;需要注意防范。 本周alphv勒索组织窃取MBC法律专业公司…

车载测试中:如何处理 bug

一&#xff1a;Jira 提交 bug 包含那些内容 二&#xff1a;如何处理现上 bug 三&#xff1a;车载相关的 bug 如何定位 四&#xff1a;遇到 bug &#xff0c;复现不出来怎么办 五&#xff1a;bug 的处理流程 一&#xff1a;Jira 提交 bug 包含那些内容二&#xff1a;如何处理现上…

C#用Array类的FindAll方法和List<T>类的Add方法按关键词在数组中检索元素并输出

目录 一、使用的方法 1. Array.FindAll(T[], Predicate) 方法 &#xff08;1&#xff09;定义 &#xff08;2&#xff09;示例 2.List类的常用方法 &#xff08;1&#xff09;List.Add(T) 方法 &#xff08;2&#xff09;List.RemoveAt(Int32) 方法 &#xff08;3&…

基于若依的ruoyi-nbcio流程管理系统自定义业务实现一种简单的动态任务标题(续)

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; https://gitee.com/nbacheng/n…

Msql-数据库死锁

实验案例 CREATE TABLE t1_deadlock ( id int(11) NOT NULL, name varchar(100) DEFAULT NULL, age int(11) NOT NULL, address varchar(255) DEFAULT NULL, PRIMARY KEY (id), KEY idx_age (age) USING BTREE, KEY idx_name (name) USING BTREE ) ENGINEInnoDB DEFAULT CHARS…

Kafka SASL_SSL双重认证

文章目录 1. 背景2. 环境3. 操作步骤3.1 生成SSL证书3.2 配置zookeeper认证3.3 配置kafka安全认证3.4 使用kafka客户端进行验证3.5 使用Java端代码进行认证 1. 背景 kafka提供了多种安全认证机制&#xff0c;主要分为SASL和SSL两大类。 SASL&#xff1a; 是一种身份验证机制&…

SRS视频服务器使用记录

SRS是一个开源的&#xff08;MIT协议&#xff09;简单高效的实时视频服务器&#xff0c;支持RTMP、WebRTC、HLS、HTTP-FLV、SRT、MPEG-DASH和GB28181等协议。 SRS媒体服务器和FFmpeg、OBS、VLC、 WebRTC等客户端配合使用&#xff0c;提供流的接收和分发的能力&#xff0c;是一个…

鸿蒙开发系列教程(十二)--布局应用:Flex布局

相关属性参数与css3的flex布局参数相似 排列方向&#xff1a;direction: FlexDirection.Row, 换行&#xff1a;wrap: FlexWrap.NoWrap, 水平垂直对齐方式&#xff1a; justifyContent: FlexAlign. SpaceBetween, alignItems: ItemAlign.Center Entry Component struct Flex…

【开源】SpringBoot框架开发高校学生管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 学生管理模块2.2 学院课程模块2.3 学生选课模块2.4 成绩管理模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 学生表3.2.2 学院课程表3.2.3 学生选课表3.2.4 学生成绩表 四、系统展示五、核心代码5.1 查询课程5.2 新…

目标检测:3采用YOLOv8 API训练自己的模型

​ 目录 ​1.YOLOv8 的新特性 2.如何使用 YOLOv8? 3使用YOLOv8训练模型 4.验证训练集 5.测试训练集 6.测验其他图片 7 其他问题 参考: 1.YOLOv8 的新特性 Ultralytics 为 YOLO 模型发布了一个全新的存储库。它被构建为 用于训练对象检测、实例分割和图像分类模型的统…