17、数据搜索、挖掘、可视化与简单数据 API 创建

数据搜索、挖掘、可视化与简单数据 API 创建

数据爬取与图可视化
  1. 单深度爬取
    • 首先定义单深度爬取,代码如下:
crawl_depth = 1
process = CrawlerProcess({
    'LOG_LEVEL': 'ERROR',
    'DEPTH_LIMIT': crawl_depth
})
process.crawl(WikipediaSpider)
spider = next(iter(process.crawlers)).spider
spider.max_items_per_page = 5
spider.max_crawl_depth = crawl_depth
process.start()
for pm in spider.linked_pages:
    print(pm.depth, pm.link, pm.child_link)
print("-"*80)
- 此代码启动了一个单深度的爬取过程,爬取完成后会打印出页面的深度、链接和子链接信息。
  1. 构建 NetworkX 图模型
    • 为了将爬取的数据转换为 NetworkX 可以使用的图模型,需要创建图并添加节点和边,代码如下:
g = nx.Graph()
nodes = {}
edges = {}
for pm in spider.linked_pages:
    if pm.title not in nodes:
        nodes[pm.title] = pm
        g.add_node(pm.title)
    if pm.child_title not in nodes:
        g.add_node(pm.child_title)
    link_key = pm.title + " ==> " + pm.child_title
    if link_key not in edges:
        edges[link_key] = link_key
        g.add_edge(pm.title, pm.child_title)
- 该代码遍历爬取结果,识别出所有唯一的节点(页面)和它们之间的链接(边),并将其添加到 NetworkX 图中。
  1. 使用 Matplotlib 绘图
    • 接下来使用 Matplotlib 绘制图,代码如下:
plt.figure(figsize=(10,8))
node_positions = nx.spring_layout(g)
nx.draw_networkx_nodes(g, node_positions, g.nodes, node_color='green', node_size=50)
nx.draw_networkx_edges(g, node_positions)
labels = { node: node for node in g.nodes() }
nx.draw_networkx_labels(g, node_positions, labels, font_size=9.5)
plt.show()
- 此代码首先使用 NetworkX 的 `spring_layout` 方法计算节点的位置,然后绘制节点、边和标签,最后显示图形。
增加爬取深度

可以通过修改代码来增加爬取深度,示例代码如下:

crawl_depth = 2
process = CrawlerProcess({
    'LOG_LEVEL': 'ERROR',
    'DEPTH_LIMIT': crawl_depth
})
process.crawl(WikipediaSpider)
spider = next(iter(process.crawlers)).spider
spider.max_items_per_page = 5
spider.max_crawl_depth = crawl_depth
process.start()

增加爬取深度后,可以看到页面之间更多的相互关系和循环关系。

计算页面间的分离度
  1. 问题描述
    • 计算任意两个页面之间的分离度,即从一个源页面到另一个页面需要经过多少个页面。这是一个图遍历问题,因为两个页面之间可能存在多条路径。
  2. 使用 A* 算法解决
    • NetworkX 提供了内置函数来解决这个问题,示例代码如下:
path = nx.astar_path(g, "Python_(programming_language)", "Dennis_Ritchie")
degrees_of_separation = int((len(path) - 1) / 2)
print("Degrees of separation: {}".format(degrees_of_separation))
for i in range(0, len(path)):
    print(" " * i, path[i])
- 该代码使用 `astar_path` 函数计算最短路径,然后根据路径长度计算分离度并打印路径信息。
创建简单 REST API
  1. 准备工作
    • Flask 是一个轻量级的 Web 框架,Flask - RESTful 是 Flask 的扩展,用于创建 REST API。可以使用以下命令安装:
pip install flask
pip install flask-restful
  1. 创建初始 API
    • 初始 API 实现代码如下:
from flask import Flask
from flask_restful import Resource, Api

app = Flask(__name__)
api = Api(app)

class JobListing(Resource):
    def get(self, job_listing_id):
        print("Request for job listing with id: " + job_listing_id)
        return {'YouRequestedJobWithId': job_listing_id}

api.add_resource(JobListing, '/', '/joblisting/<string:job_listing_id>')

if __name__ == '__main__':
    print("Starting the job listing API")
    app.run(debug=True)
- 此代码创建了一个简单的 REST API,当接收到 `/joblisting/<job_listing_id>` 的 GET 请求时,会返回包含请求 ID 的 JSON 数据。
  1. 运行和测试 API
    • 可以使用以下命令运行 API:
python api.py
- 然后使用 `curl` 命令测试 API:
curl localhost:5000/joblisting/1
- 测试结果会返回类似 `{"YouRequestedJobWithId": "1"}` 的 JSON 数据。
集成 REST API 与刮取代码
  1. 准备工作
    • 需要将之前用于刮取 StackOverflow 职位列表的代码封装成一个模块 sojobs ,其中 scraping.py 文件中的 get_job_listing_info 函数用于获取职位列表信息,代码如下:
def get_job_listing(job_listing_id):
    print("Got a request for a job listing with id: " + job_listing_id)
    req = requests.get("https://stackoverflow.com/jobs/" + job_listing_id)
    content = req.text
    bs = BeautifulSoup(content, "lxml")
    script_tag = bs.find("script", {"type": "application/ld+json"})
    job_listing_contents = json.loads(script_tag.contents[0])
    desc_bs = BeautifulSoup(job_listing_contents["description"], "lxml")
    just_text = desc_bs.find_all(text=True)
    joined = ' '.join(just_text)
    tokens = word_tokenize(joined)
    stop_list = stopwords.words('english')
    with_no_stops = [word for word in tokens if word.lower() not in stop_list]
    two_grammed = tech_2grams(with_no_stops)
    cleaned = remove_punctuation(two_grammed)
    result = {
        "ID": job_listing_id,
        "JSON": job_listing_contents,
        "TextOnly": just_text,
        "CleanedWords": cleaned
    }
    return json.dumps(result)
  1. 集成 API 与刮取代码
    • 修改 API 代码以调用 get_job_listing_info 函数,代码如下:
from flask import Flask
from flask_restful import Resource, Api
from sojobs.scraping import get_job_listing_info

app = Flask(__name__)
api = Api(app)

class JobListing(Resource):
    def get(self, job_listing_id):
        print("Request for job listing with id: " + job_listing_id)
        listing = get_job_listing_info(job_listing_id)
        print("Got the following listing as a response: " + listing)
        return listing

api.add_resource(JobListing, '/', '/joblisting/<string:job_listing_id>')

if __name__ == '__main__':
    print("Starting the job listing API")
    app.run(debug=True)
  1. 测试集成后的 API
    • 运行 API 后,使用 curl 命令测试:
curl localhost:5000/joblisting/122517
- 测试结果会返回包含职位列表详细信息的 JSON 数据。
添加 API 以查找职位列表的技能
  1. 添加刮取函数
    • sojobs 模块中添加 get_job_listing_skills 函数,代码如下:
def get_job_listing_skills(job_listing_id):
    print("Got a request for a job listing skills with id: " + job_listing_id)
    req = requests.get("https://stackoverflow.com/jobs/" + job_listing_id)
    content = req.text
    bs = BeautifulSoup(content, "lxml")
    script_tag = bs.find("script", {"type": "application/ld+json"})
    job_listing_contents = json.loads(script_tag.contents[0])
    skills = job_listing_contents['skills']
    return json.dumps(skills)
- 该函数用于获取职位列表的技能信息。
  1. 修改 API 以调用新函数
    • 在 API 代码中添加新的类 JobListingSkills ,代码如下:
class JobListingSkills(Resource):
    def get(self, job_listing_id):
        print("Request for job listing's skills with id: " + job_listing_id)
        skills = get_job_listing_skills(job_listing_id)
        print("Got the following skills as a response: " + skills)
        return skills

api.add_resource(JobListingSkills, '/', '/joblisting/<string:job_listing_id>/skills')
- 此代码定义了一个新的 API 端点,用于获取职位列表的技能信息。

总结

本文介绍了数据爬取、图可视化、计算页面分离度以及创建和扩展简单 REST API 的相关知识和代码实现。通过这些技术,可以更好地处理和分析网页数据,并将数据以 API 的形式提供给其他应用程序使用。

流程图

graph LR
    A[开始单深度爬取] --> B[构建 NetworkX 图模型]
    B --> C[使用 Matplotlib 绘图]
    A --> D[增加爬取深度]
    D --> B
    B --> E[计算页面分离度]
    E --> F[创建简单 REST API]
    F --> G[集成 REST API 与刮取代码]
    G --> H[添加 API 以查找职位列表的技能]

表格

功能 代码文件 关键函数
单深度爬取 - -
构建图模型 - -
绘图 - -
计算分离度 08/07_degrees_of_separation.py nx.astar_path
创建初始 API 09/01/api.py JobListing.get
集成刮取代码 09/02/api.py get_job_listing_info
查找职位技能 09/03/api.py get_job_listing_skills

数据搜索、挖掘、可视化与简单数据 API 创建

数据存储与缓存:使用 Elasticsearch

在处理大量数据时,数据的存储和缓存至关重要。Elasticsearch 是一个强大的开源搜索和分析引擎,可以用于存储和快速检索数据。下面介绍如何将爬取的数据存储到 Elasticsearch 中,并在需要时进行缓存查询。

  1. 存储数据到 Elasticsearch
    • 首先,确保已经安装并启动了 Elasticsearch。然后,在 Python 中使用 elasticsearch 库来连接和操作 Elasticsearch。以下是一个简单的示例代码,将爬取的职位列表数据存储到 Elasticsearch 中:
from elasticsearch import Elasticsearch

# 连接到 Elasticsearch
es = Elasticsearch([{'host': 'localhost', 'port': 9200}])

def store_job_listing_to_es(job_listing_id, job_listing_data):
    try:
        # 索引名称
        index_name = 'job_listings'
        doc = {
            'id': job_listing_id,
            'data': job_listing_data
        }
        # 存储数据到 Elasticsearch
        es.index(index=index_name, id=job_listing_id, body=doc)
        print(f"Job listing {job_listing_id} stored in Elasticsearch.")
    except Exception as e:
        print(f"Error storing job listing {job_listing_id} in Elasticsearch: {e}")
- 在调用 `get_job_listing_info` 函数获取职位列表数据后,可以调用 `store_job_listing_to_es` 函数将数据存储到 Elasticsearch 中。
  1. 检查 Elasticsearch 缓存
    • 在进行新的爬取之前,可以先检查 Elasticsearch 中是否已经存在所需的数据。以下是一个检查缓存的示例代码:
def check_es_cache(job_listing_id):
    try:
        # 索引名称
        index_name = 'job_listings'
        # 检查数据是否存在
        result = es.get(index=index_name, id=job_listing_id, ignore=[404])
        if result.get('found'):
            print(f"Job listing {job_listing_id} found in Elasticsearch cache.")
            return result['_source']['data']
        else:
            print(f"Job listing {job_listing_id} not found in Elasticsearch cache.")
            return None
    except Exception as e:
        print(f"Error checking Elasticsearch cache for job listing {job_listing_id}: {e}")
        return None
- 在调用 `get_job_listing_info` 函数之前,可以先调用 `check_es_cache` 函数检查缓存。如果数据存在,则直接使用缓存数据;否则,进行新的爬取并存储到 Elasticsearch 中。
优化 API 性能

为了提高 API 的性能和响应速度,可以采取以下几种优化措施:

  1. 缓存机制
    • 除了使用 Elasticsearch 进行数据缓存外,还可以在 API 层实现简单的内存缓存。例如,使用 Python 的 functools.lru_cache 装饰器来缓存函数的返回值:
import functools

@functools.lru_cache(maxsize=128)
def get_job_listing_info_cached(job_listing_id):
    return get_job_listing_info(job_listing_id)
- 然后在 API 代码中调用 `get_job_listing_info_cached` 函数代替 `get_job_listing_info` 函数。
  1. 异步处理
    • 对于耗时的操作,如爬取数据和存储到 Elasticsearch,可以使用异步编程来提高并发性能。Python 的 asyncio aiohttp 库可以用于实现异步爬取和存储。以下是一个简单的异步爬取示例:
import asyncio
import aiohttp

async def async_get_job_listing(job_listing_id):
    async with aiohttp.ClientSession() as session:
        url = f"https://stackoverflow.com/jobs/{job_listing_id}"
        async with session.get(url) as response:
            content = await response.text()
            # 后续处理代码...
            return content
扩展 API 功能

除了现有的功能,还可以进一步扩展 API 的功能,以满足更多的需求。

  1. 批量查询
    • 可以添加一个新的 API 端点,支持批量查询职位列表信息。以下是一个简单的实现示例:
class JobListingsBatch(Resource):
    def get(self, job_listing_ids):
        ids = job_listing_ids.split(',')
        results = []
        for id in ids:
            listing = get_job_listing_info(id)
            results.append(listing)
        return results

api.add_resource(JobListingsBatch, '/', '/joblistings/<string:job_listing_ids>')
- 调用该 API 时,可以传入多个职位列表 ID,用逗号分隔,如 `curl localhost:5000/joblistings/1,2,3`。
  1. 排序和过滤
    • 可以添加排序和过滤功能,让用户可以根据不同的条件对职位列表进行排序和过滤。例如,添加一个新的 API 端点,支持按技能进行过滤:
class JobListingsFilterBySkills(Resource):
    def get(self, skills):
        skill_list = skills.split(',')
        all_listings = []
        # 获取所有职位列表
        # ...
        filtered_listings = []
        for listing in all_listings:
            listing_skills = get_job_listing_skills(listing['id'])
            if any(skill in listing_skills for skill in skill_list):
                filtered_listings.append(listing)
        return filtered_listings

api.add_resource(JobListingsFilterBySkills, '/', '/joblistings/filter/skills/<string:skills>')

流程图

graph LR
    A[开始] --> B[检查 Elasticsearch 缓存]
    B -- 数据存在 --> C[使用缓存数据]
    B -- 数据不存在 --> D[爬取数据]
    D --> E[存储数据到 Elasticsearch]
    E --> F[返回数据]
    C --> F
    G[API 请求] --> H[缓存机制]
    H --> I[异步处理]
    I --> J[批量查询/排序过滤]
    J --> F

表格

功能 代码实现 关键函数
存储数据到 Elasticsearch - store_job_listing_to_es
检查 Elasticsearch 缓存 - check_es_cache
内存缓存 - functools.lru_cache
异步爬取 - async_get_job_listing
批量查询 新 API 端点 JobListingsBatch.get
排序和过滤 新 API 端点 JobListingsFilterBySkills.get

总结

本文详细介绍了数据爬取、图可视化、计算页面分离度、创建和扩展简单 REST API 的相关知识和代码实现。同时,还介绍了如何使用 Elasticsearch 进行数据存储和缓存,以及如何优化 API 性能和扩展 API 功能。通过这些技术和方法,可以更好地处理和分析网页数据,并将数据以灵活、高效的 API 形式提供给其他应用程序使用。希望这些内容对大家在数据处理和 API 开发方面有所帮助。

内容概要:本文档介绍了基于3D FDTD(时域有限差分)方法在MATLAB平台上对微带线馈电的矩形天线进行仿真分析的技术方案,重点在于模拟超MATLAB基于3D FDTD的微带线馈矩形天线分析[用于模拟超宽带脉冲通过线馈矩形天线的传播,以计算微带结构的回波损耗参数]宽带脉冲信号通过天线结构的传播过程,并计算微带结构的回波损耗参数(S11),以评估天线的匹配性能和辐射特性。该方法通过建立三维电磁场模型,精确求解麦克斯韦方程组,适用于高频电磁仿真,能够有效分析天线在宽频带内的响应特性。文档还提及该资源属于一个涵盖多个科研方向的综合性MATLAB仿真资源包,涉及通信、信号处理、电力系统、机器学习等多个领域。; 适合人群:具备电磁场微波技术基础知识,熟悉MATLAB编程及数值仿真的高校研究生、科研人员及通信工程领域技术人员。; 使用场景及目标:① 掌握3D FDTD方法在天线仿真中的具体实现流程;② 分析微带天线的回波损耗特性,优化天线设计参数以提升宽带匹配性能;③ 学习复杂电磁问题的数值建模仿真技巧,拓展在射频无线通信领域的研究能力。; 阅读建议:建议读者结合电磁理论基础,仔细理解FDTD算法的离散化过程和边界条件设置,运行并调试提供的MATLAB代码,通过调整天线几何尺寸和材料参数观察回波损耗曲线的变化,从而深入掌握仿真原理工程应用方法。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值