博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

数据采集与融合技术 作业3

Posted on 2024-11-07 17:55  Bluemming  阅读(7)  评论(0编辑  收藏  举报

Gitee链接地址:https://gitee.com/Bluemingiu/project/tree/master/3

作业①

  • 要求:指定一个网站,爬取这个网站中的所有图片,例如:中国气象网(http://www.weather.com.cn)。使用scrapy框架分别实现单线程和多线程的方式爬取。设计爬取前47页的所有图片。

  • 输出信息: 将下载的Url信息在控制台输出,并将下载的图片存储在images子文件中,并给出截图。

1. 实验过程

核心代码

提取图片链接

images = response.css('img::attr(src)').getall()

处理图片链接

for img_url in images:
    full_url = response.urljoin(img_url)
    self.log(f'Downloading image: {full_url}')
    yield {
        'image_urls': [full_url]
    }

单线程:

直接使用命令运行

scrapy crawl weather -o images.json

多线程:

settings.py 文件中,设置 CONCURRENT_REQUESTS 为 16

输出结果

  • 终端:

  • images.json:

  • images文件夹

2. 心得体会

通过完成这个任务,我对使用 Scrapy 框架进行网页数据爬取有了更深入的理解,特别是在处理网页中的图片资源和翻页机制时。一方面,掌握了如何使用 CSS 选择器提取网页中的元素,并通过 response.urljoin 处理相对路径问题,确保获得完整的图片链接。另一方面,实践了如何控制爬虫的页数和翻页,通过构造分页 URL 实现多页数据的爬取。最重要的是,我意识到爬虫设计中的一些常见挑战,比如如何正确处理分页、如何处理页面中的相对路径以及如何合理调试和优化爬虫。总的来说,这个任务让我更加熟悉了 Scrapy 的基本操作和一些高级技巧,为以后的数据爬取项目打下了坚实的基础。

作业②

  • 要求:熟练掌握 scrapy 中 Item、Pipeline 数据的序列化输出方法;使用scrapy框架+Xpath+MySQL数据库存储技术路线爬取股票相关信息。候选网站:东方财富网:https://www.eastmoney.com/
  • 输出信息:MySQL数据库存储和输出格式如下:表头英文命名例如:序号id,股票代码:bStockNo……,由同学们自行定义设计。

1. 实验过程

核心代码

  • 发送请求和获取响应
def start_requests(self):
    for page in range(1, 8):  # 爬取前 7 页的数据
        url = self.api_url.format(page=page)
        yield scrapy.Request(url=url, callback=self.parse)
  • 处理 JSONP 响应并解析 JSON 数据
def parse(self, response):
    jsonp_match = re.search(r'\((.*?)\)', response.text)
    print(jsonp_match)
    if jsonp_match:
        json_data = json.loads(jsonp_match.group(1))
        stocks = json_data.get('data', {}).get('diff', [])
  • 提取股票数据并封装为 Item
item['bStockNo'] = stock.get('f12')  # 股票代码
item['bStockName'] = stock.get('f14')  # 股票名称
item['latestPrice'] = stock.get('f2')  # 最新报价
item['priceChange'] = stock.get('f3')  # 涨跌幅
item['priceChangeValue'] = stock.get('f4')  # 涨跌额
item['volume'] = stock.get('f5')  # 成交量
item['amplitude'] = stock.get('f6')  # 振幅
item['high'] = stock.get('f7')  # 最高价
item['low'] = stock.get('f8')  # 最低价
item['open'] = stock.get('f9')  # 今开盘
item['close'] = stock.get('f10')  # 昨收盘
  • 修改settings.py:
BOT_NAME = 'stock_spider'

SPIDER_MODULES = ['stock_spider.spiders']
NEWSPIDER_MODULE = 'stock_spider.spiders'

ITEM_PIPELINES = {
    'stock_spider.pipelines.MySQLPipeline': 1,
}

# 禁用 robots.txt 规则
ROBOTSTXT_OBEY = False

# 自定义请求头
DEFAULT_REQUEST_HEADERS = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
    'Accept-Language': 'en-US,en;q=0.9',
    'Accept-Encoding': 'gzip, deflate, br',
    'Connection': 'keep-alive',
    'Upgrade-Insecure-Requests': '1',
}

# 启用随机 User-Agent
DOWNLOADER_MIDDLEWARES = {
    'scrapy_user_agents.middlewares.RandomUserAgentMiddleware': 400,
}
  • 修改pipelines.py:
def open_spider(self, spider):
        # 打开数据库连接
        try:
            self.conn = mysql.connector.connect(
                host='localhost',
                database='stock_db',
                user='root',
                password='iulze0516'
            )
            self.cursor = self.conn.cursor()
            print("Connected to MySQL")
        except Error as e:
            print(f"Error: {e}")
    
    def close_spider(self, spider):
        # 关闭数据库连接
        self.conn.commit()
        self.cursor.close()
        self.conn.close()
        print("MySQL connection closed")

    def process_item(self, item, spider):
        # 插入数据到数据库
        sql = """INSERT INTO stocks 
                 (bStockNo, bStockName, latestPrice, priceChange, priceChangeValue, 
                  volume, amplitude, high, low, open, close)
                 VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"""
        
        values = (
            item['bStockNo'], item['bStockName'], item['latestPrice'], 
            item['priceChange'], item['priceChangeValue'], item['volume'], 
            item['amplitude'], item['high'], item['low'], item['open'], 
            item['close']
        )
        
        self.cursor.execute(sql, values)
        return item
  • 修改items.py:
class StockItem(scrapy.Item):
    id = scrapy.Field() # 序号   
    bStockNo = scrapy.Field() # 股票代码   
    bStockName = scrapy.Field() # 股票名称    
    latestPrice = scrapy.Field() # 最新报价   
    priceChange = scrapy.Field() # 涨跌幅    
    priceChangeValue = scrapy.Field() # 涨跌额  
    volume = scrapy.Field() # 成交量    
    amplitude = scrapy.Field() # 振幅    
    high = scrapy.Field() # 最高   
    low = scrapy.Field() # 最低    
    open = scrapy.Field() # 今开
    close = scrapy.Field() # 昨收

输出结果

2. 心得体会

完成这个任务让我深刻体会到在数据爬取过程中,解析复杂数据格式和处理分页请求的重要性。首先,通过正则表达式提取 JSONP 响应并将其转换为标准 JSON,是处理动态加载数据时常见的挑战,这让我更清楚地认识到如何应对各种数据格式和网络请求的处理。其次,设置分页机制并通过 start_requests 动态生成请求 URL,对于高效爬取大量数据至关重要,掌握分页的控制技巧能够有效避免重复抓取和遗漏数据。总的来说,这次任务加强了我对 Scrapy 框架的应用能力,尤其是在爬取复杂 API 数据、处理数据格式和控制爬虫流程方面的理解,也让我更好地掌握了如何从网页或 API 中高效提取所需数据。

作业③

  • 要求:熟练掌握 scrapy 中 Item、Pipeline 数据的序列化输出方法;使用scrapy框架+Xpath+MySQL数据库存储技术路线爬取外汇网站数据。候选网站:中国银行网:https://www.boc.cn/sourcedb/whpj/

1. 实验过程

核心代码

  • 获取数据行:
rows = response.xpath('//table//tr[position()>1]')
  • 提取数据并清理:
item['currency'] = row.xpath('td[1]/text()').get(default='').strip() 
item['cbp'] = row.xpath('td[2]/text()').get(default='').strip()  
item['tsp'] = row.xpath('td[3]/text()').get(default='').strip() 
item['tbp'] = row.xpath('td[4]/text()').get(default='N/A').strip() 
item['csp'] = row.xpath('td[5]/text()').get(default='').strip() 
item['time'] = row.xpath('td[7]/text()').get(default='').strip() 
  • 修改settings.py:
BOT_NAME = 'forex_spider'

SPIDER_MODULES = ['forex_spider.spiders']
NEWSPIDER_MODULE = 'forex_spider.spiders'

ITEM_PIPELINES = {
    'forex_spider.pipelines.MySQLPipeline': 1,
}

DEFAULT_REQUEST_HEADERS = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
    'Accept-Language': 'en-US,en;q=0.9',
    'Accept-Encoding': 'gzip, deflate, br',
    'Connection': 'keep-alive',
    'Upgrade-Insecure-Requests': '1',
}
  • 修改pipelines.py:
def open_spider(self, spider):
        # 连接到 MySQL 数据库
        self.conn = mysql.connector.connect(
            host='localhost',
            user='root',
            password='iulze0516',  
            database='forex_db'     
        )
        self.cursor = self.conn.cursor()

    def process_item(self, item, spider):
        # 插入数据到数据库
        insert_query = """
            INSERT INTO forex_data (currency, tbp, cbp, tsp, csp, time)
            VALUES (%s, %s, %s, %s, %s, %s)
        """
        data = (
            item['currency'],
            item['tbp'],
            item['cbp'],
            item['tsp'],
            item['csp'],
            item['time']
        )
        self.cursor.execute(insert_query, data)
        self.conn.commit()
        return item

    def close_spider(self, spider):
        # 关闭数据库连接
        self.cursor.close()
        self.conn.close()
  • 修改items.py:
class ForexItem(scrapy.Item):
    currency = scrapy.Field()       
    tbp = scrapy.Field()    
    cbp = scrapy.Field()          
    tsp = scrapy.Field()            
    csp = scrapy.Field()          
    time = scrapy.Field()          

输出结果

2. 心得体会

完成这个任务让我深入理解了 Scrapy 框架的使用,特别是在处理网页数据提取和清理方面。通过掌握 XPath 选择器,我能够精确提取网页中的元素,并排除表头等无关数据。此外,我学会了使用 .get(default='') 和 .strip() 等方法处理空值和格式不规范的数据,确保爬取的内容完整且符合预期。Scrapy 中的 yield 使得数据能够逐条返回,节省了内存并提高了爬取效率。在数据存储方面,利用 Scrapy Pipeline 我能够将爬取的数据有效地存入数据库或文件中,这为后续的数据处理和分析打下了基础。整个过程中,调试和错误处理的经验也让我意识到,数据抓取并非一蹴而就,往往需要反复优化代码。总的来说,这个任务不仅加深了我对 Scrapy 的理解,还提高了我在实际项目中处理数据的能力。