102302109-胡贝贝-作业4

作业①:
(1)实验内容及结果
熟练掌握 Selenium 查找HTML元素、爬取Ajax网页数据、等待HTML元素等内容。
使用Selenium框架+ MySQL数据库存储技术路线爬取“沪深A股”、“上证A股”、“深证A股”3个板块的股票数据信息。
核心代码:


class StockDataSpider(scrapy.Spider):
    name = 'stock_data'
    allowed_domains = ['quote.eastmoney.com']
    # 定义要爬取的市场及其API参数
    markets = {
        '沪深A股': {
            'api_fs': 'm:0+t:6,m:0+t:80,m:1+t:2,m:1+t:23',
            'url_suffix': 'hs_a_board'
        },
        '上证A股': {
            'api_fs': 'm:1+t:2',
            'url_suffix': 'sh_a_board'
        },
        '深证A股': {
            'api_fs': 'm:0+t:6',
            'url_suffix': 'sz_a_board'
        }
    }
    def start_requests(self):
        self.logger.info(" 开始爬取东方财富网股票数据...")
        for market_name, market_info in self.markets.items():
            web_url = f"http://quote.eastmoney.com/center/gridlist.html#{market_info['url_suffix']}"
            # API URL
            api_url = self.construct_api_url(market_info['api_fs'])
            yield scrapy.Request(
                url=api_url,
                callback=self.parse_api,
                meta={
                    'market_name': market_name,
                    'web_url': web_url
                },
                headers={
                    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
                    'Referer': web_url,
                    'Accept': 'application/json, text/plain, */*',
                    'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
                    'Origin': 'http://quote.eastmoney.com'
                },
                dont_filter=True
            )
    def construct_api_url(self, fs_param):
        """构造API URL"""
        base_url = "http://82.push2.eastmoney.com/api/qt/clist/get"
        params = {
            'pn': '1',
            'pz': '5000',
            'po': '1',
            'np': '1',
            'ut': 'bd1d9ddb04089700cf9c27f6f7426281',
            'fltt': '2',
            'invt': '2',
            'fid': 'f3',
            'fs': fs_param,
            'fields': 'f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f12,f13,f14,f15,f16,f17,f18,f20,f21,f23,f24,f25,f22,f11,f62,f128,f136,f115,f152',
            '_': str(int(datetime.now().timestamp() * 1000))
        }
        param_str = '&'.join([f"{k}={v}" for k, v in params.items()])
        return f"{base_url}?{param_str}"
    def parse_api(self, response):
        market_name = response.meta['market_name']
        self.logger.info(f" 开始解析 {market_name} 数据...")
        try:
            data = json.loads(response.text)
            stocks = data.get('data', {}).get('diff', [])
            self.logger.info(f" 从API获取到 {len(stocks)} 只{market_name}数据")
            current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
            processed_count = 0
            for index, stock in enumerate(stocks):
                item = StockItem()
                item['id'] = index + 1
                item['stock_code'] = stock.get('f12', '')  # 股票代码
                item['stock_name'] = stock.get('f14', '')  # 股票名称
                item['latest_price'] = stock.get('f2', 0)  # 最新价
                item['change_percent'] = stock.get('f3', 0)  # 涨跌幅
                item['change_amount'] = stock.get('f4', 0)  # 涨跌额
                item['volume'] = self.format_volume(stock.get('f5', 0))  # 成交量
                item['turnover'] = self.format_turnover(stock.get('f6', 0))  # 成交额
                item['amplitude'] = stock.get('f7', 0)  # 振幅
                item['high_price'] = stock.get('f15', 0)  # 最高
                item['low_price'] = stock.get('f16', 0)  # 最低
                item['open_price'] = stock.get('f17', 0)  # 今开
                item['previous_close'] = stock.get('f18', 0)  # 昨收
                item['market_type'] = market_name
                item['crawl_time'] = current_time
                if item['stock_code'] and item['stock_name']:
                    processed_count += 1
                    if processed_count <= 5:
                        self.logger.info(
                            f" 示例数据: {item['stock_name']}({item['stock_code']}) - 价格: {item['latest_price']}")
                    yield item
            self.logger.info(f" {market_name} 数据处理完成,共处理 {processed_count} 条有效数据")
        except Exception as e:
            self.logger.error(f" 解析{market_name}数据失败: {e}")
            self.logger.debug(f"响应内容: {response.text[:500]}")
    def format_volume(self, volume):
        """格式化成交量"""
        try:
            volume = float(volume)
            if volume >= 100000000:
                return f"{volume / 100000000:.2f}亿"
            elif volume >= 10000:
                return f"{volume / 10000:.2f}万"
            else:
                return f"{volume:.0f}"
        except (ValueError, TypeError):
            return "0"
    def format_turnover(self, turnover):
        """格式化成交额"""
        try:
            turnover = float(turnover)
            if turnover >= 100000000:
                return f"{turnover / 100000000:.2f}亿元"
            elif turnover >= 10000:
                return f"{turnover / 10000:.2f}万元"
            else:
                return f"{turnover:.2f}元"
        except (ValueError, TypeError):
            return "0"

输出信息:

image

image
image
image

image

Gitee文件夹链接:https://gitee.com/hu_beibei/data-collection-practice/tree/master/102302109_胡贝贝_作业4/作业一
(2)实验心得
通过完成沪深A股数据爬取项目,我深入掌握了Selenium在动态网页数据抓取中的应用技巧,特别是对Ajax加载内容的处理和元素等待机制。在数据存储环节,通过设计合理的MySQL表结构和字段映射关系,不仅实现了数据的有效存储,还加深了对数据库设计与Python交互的理解。

作业②:
(1)实验内容及结果
熟练掌握 Selenium 查找HTML元素、实现用户模拟登录、爬取Ajax网页数据、等待HTML元素等内容。
使用Selenium框架+MySQL爬取中国mooc网课程资源信息(课程号、课程名称、学校名称、主讲教师、团队成员、参加人数、课程进度、课程简介)
核心代码:

 def extract_course_info(self, url, expected_school, expected_name, expected_teacher):
        """提取课程信息"""
        print(f"\n访问: {url}")
        
        try:
            self.driver.get(url)
            time.sleep(3)
            
            # 获取页面标题
            title = self.driver.title
            
            # 清理课程名称
            if expected_name:
                course_name = expected_name
            else:
                course_name = title.split('_')[0] if '_' in title else title
                course_name = self.clean_text(course_name)
            
            # 获取学校名称
            school_name = expected_school
            
            # 获取教师名称
            teacher_name = expected_teacher
            
            # 提取参与人数
            participants = 0
            try:
                # 尝试多种方式查找参与人数
                body_text = self.driver.find_element(By.TAG_NAME, 'body').text
                
                # 多种人数匹配模式
                patterns = [
                    r'(\d{1,3}(?:,\d{3})*)\s*人选课',
                    r'(\d+)\s*人参加',
                    r'已有\s*(\d+)\s*人',
                    r'(\d+)\s*位同学',
                    r'选课人数[::]\s*(\d+)',
                    r'(\d+)\s*人学习'
                ]
                
                for pattern in patterns:
                    match = re.search(pattern, body_text)
                    if match:
                        num_str = match.group(1).replace(',', '')
                        try:
                            participants = int(num_str)
                            if participants > 0:
                                break
                        except:
                            continue
            except:
                participants = 0
            
            # 提取课程简介
            course_brief = "暂无简介"
            try:
                # 查找描述元素
                selectors = [
                    'meta[name="description"]',
                    '.course-description',
                    '.m-course-desc',
                    '.course-summary'
                ]
                
                for selector in selectors:
                    try:
                        if selector == 'meta[name="description"]':
                            element = self.driver.find_element(By.CSS_SELECTOR, selector)
                            text = element.get_attribute('content')
                        else:
                            element = self.driver.find_element(By.CSS_SELECTOR, selector)
                            text = element.text
                        
                        if text and len(text) > 30:
                            course_brief = self.clean_text(text)[:300]
                            break
                    except:
                        continue
                
                # 如果还没找到,从页面提取
                if course_brief == "暂无简介":
                    body_text = self.driver.find_element(By.TAG_NAME, 'body').text[:1000]
                    # 找到相对较长的描述性段落
                    lines = body_text.split('\n')
                    for line in lines:
                        line_clean = self.clean_text(line)
                        if 50 < len(line_clean) < 200 and any(word in line_clean for word in ['课程', '学习', '教学', '简介']):
                            course_brief = line_clean[:300]
                            break
            except:
                course_brief = "暂无简介"
            
            # 构建课程信息
            course_info = {
                'course_name': course_name,
                'college_name': school_name,
                'main_teacher': teacher_name,
                'participants': participants,
                'course_brief': course_brief,
                'course_url': url,
                'team_members': ''
            }
            
            print(f"课程名称: {course_name}")
            print(f"学校名称: {school_name}")
            print(f"主讲教师: {teacher_name}")
            print(f"参与人数: {participants}")
            print(f"课程简介: {course_brief[:50]}...")
            
            return course_info
            
        except Exception as e:
            print(f"提取失败: {e}")
            import traceback
            traceback.print_exc()
            return None

输出信息:
image
image
image
image

Gitee文件夹链接:https://gitee.com/hu_beibei/data-collection-practice/tree/master/102302109_胡贝贝_作业4/作业二
(2)实验心得
中国MOOC网爬取项目让我全面体验了模拟登录和复杂页面结构的处理过程。在应对动态加载课程信息时,我学会了如何通过多维度定位策略确保数据抓取的准确性。通过将非结构化网页数据转化为规范的数据库记录,我提升了数据清洗和格式转换的能力,也深刻体会到用户模拟技术在反爬策略应对中的重要性。

作业③:
(1)实验内容及结果
掌握大数据相关服务,熟悉Xshell的使用
完成文档 华为云_大数据实时分析处理实验手册-Flume日志采集实验(部分)v2.docx 中的任务,即为下面5个任务,具体操作见文档。
环境搭建:
任务一:开通MapReduce服务
image
image
image

实时分析开发实战:

任务一:Python脚本生成测试数据
image

任务二:配置Kafka
image

任务三: 安装Flume客户端
image

任务四:配置Flume采集数据
image
image
image
image

(2)实验心得
Flume日志采集实验让我首次接触完整的大数据采集流水线。从云端环境搭建到多组件协调配置,我理解了分布式系统中各服务组件的角色定位和协作原理。通过亲手部署数据生成、传输和采集的完整链路,我对实时数据处理架构有了直观认识,这种从编码到运维的全流程实践极大拓展了我的技术视野。

posted @ 2025-12-10 13:55  茶农123  阅读(0)  评论(0)    收藏  举报