使用Python3实现火车票查询工具:车站、车次、票价与余票信息一键查询
今天,我们要用它来实现一个简单且实用的火车票查询工具,以便我们能够更便捷地查询车票信息。[]
我们将实现以下功能:
车站信息查询
车次信息查询
79269]
自动保存查询结果
环境准备
[]
<p><pre> <section><span leaf=">bash</span>
<span></span>
</section></pre></p>
https://img2.baidu.com/it/u=2080177346,1402829041&fm=253&fmt=JPEG&app=138&f=JPEG?w=628&h=500
<p><pre class="code-snippet__js" data-lang=""> <code><span leaf=""><span cls="code-snippet__plaintext">pip install requests</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">pip install prettytable</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">pip install station_data</span></span></code></pre></p>
核心代码实现
首先,我们来实现主要的查询类:
<p><pre class="code-snippet__js" data-lang="python"> <code><span leaf=""><span class="code-snippet__keyword">import</span><span class="code-snippet__plaintext"> requests</span></span></code><code><span leaf=""><span class="code-snippet__keyword">import</span><span class="code-snippet__plaintext"> json</span></span></code><code><span leaf=""><span class="code-snippet__keyword">from</span><span class="code-snippet__plaintext"> prettytable </span><span class="code-snippet__keyword">import</span><span class="code-snippet__plaintext"> PrettyTable</span></span></code><code><span leaf=""><span class="code-snippet__keyword">from</span><span class="code-snippet__plaintext"> datetime </span><span class="code-snippet__keyword">import</span><span class="code-snippet__plaintext"> datetime</span></span></code><code><span leaf=""><span class="code-snippet__keyword">class</span><span class="code-snippet__plaintext"> </span><span class="code-snippet__title">TrainQuery</span><span class="code-snippet__plaintext">:</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">def</span><span class="code-snippet__plaintext"> </span><span class="code-snippet__title">__init__</span><span class="code-snippet__plaintext">(</span><span class="code-snippet__params">self</span><span class="code-snippet__plaintext">):</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">创建一个会话对象 self.session,该对象是通过 requests.Session()函数创建的。</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> self.headers = {</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__string">'User-Agent'</span><span class="code-snippet__plaintext">: </span><span class="code-snippet__string">Mozilla/5.0 表示这是一个 Mozilla 公司的浏览器。它运行在 Windows NT 10.0 系统上,且系统为 64 位(Win64)。同时,它的内核是 WebKit/537.36,这种内核类似于 Gecko 内核。该浏览器的版本是 Chrome/91.0.4472.124,并且其渲染引擎是 Safari/537.36。</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> }</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">self.station_map 等于 self._load_station_data() 这个操作的结果。</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">def</span><span class="code-snippet__plaintext"> </span><span class="code-snippet__title">_load_station_data</span><span class="code-snippet__plaintext">(</span><span class="code-snippet__params">self</span><span class="code-snippet__plaintext">:</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__string">"""加载车站数据"""</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> station_map = {}</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">try</span><span class="code-snippet__plaintext">:</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">with</span><span class="code-snippet__plaintext"> </span><span class="code-snippet__built_in">open</span><span class="code-snippet__plaintext">(</span><span class="code-snippet__string">'station_data.json'</span><span class="code-snippet__plaintext">, </span><span class="code-snippet__string">'r'</span><span class="code-snippet__plaintext">, encoding=</span><span class="code-snippet__string">'utf-8'</span><span class="code-snippet__plaintext">) </span><span class="code-snippet__keyword">as</span><span class="code-snippet__plaintext"> f:</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">使用`f`加载的内容被赋值给了`station_map`,`json.load(f)`完成了从文件`f`中读取 JSON 数据并将其转换为 Python 对象的操作,最终得到的结果存储在`station_map`中。</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">except</span><span class="code-snippet__plaintext"> FileNotFoundError:</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__built_in">print</span><span class="code-snippet__plaintext">(</span><span class="code-snippet__string">"站点数据文件不存在,请先更新站点数据"</span><span class="code-snippet__plaintext">)</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">return</span><span class="code-snippet__plaintext"> station_map</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">def</span><span class="code-snippet__plaintext"> </span><span class="code-snippet__title">query_tickets</span><span class="code-snippet__plaintext">(</span><span class="code-snippet__params">自我、起始站点、到达站点、日期</span><span class="code-snippet__plaintext">):</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__string">"""查询车票信息"""</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">self.station_map 获取到的内容赋值给 from_code,其中获取的是 from_station 对应的信息</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">to_code 等于 self.station_map 获取到的 to_station 对应的内容</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">if</span><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">not</span><span class="code-snippet__plaintext"> (from_code </span><span class="code-snippet__keyword">and</span><span class="code-snippet__plaintext"> to_code):</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">return</span><span class="code-snippet__plaintext"> </span><span class="code-snippet__string">"站点信息有误,请检查站点名称"</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> url = (</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__string">f 的链接为 https://kyfw.12306.cn/otn/leftTicket/query?</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__string"><span class="code-snippet__plaintext">f'leftTicketDTO.train_date=</span></span><span class="code-snippet__string"><span class="code-snippet__subst">{date}</span></span><span class="code-snippet__string"><span class="code-snippet__plaintext">&'</span></span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__string"><span class="code-snippet__plaintext">f'leftTicketDTO.from_station=</span></span><span class="code-snippet__string"><span class="code-snippet__subst">{from_code}</span></span><span class="code-snippet__string"><span class="code-snippet__plaintext">&'</span></span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__string"><span class="code-snippet__plaintext">f'leftTicketDTO.to_station=</span></span><span class="code-snippet__string"><span class="code-snippet__subst">{to_code}</span></span><span class="code-snippet__string"><span class="code-snippet__plaintext">&'</span></span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__string">f'purpose_codes=ADULT'</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> )</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">try</span><span class="code-snippet__plaintext">:</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">使用 self.session 获取 url 对应的响应,同时设置请求头为 self.headers ,获取到的响应赋值给 response 。</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">result 等于 response 的 json 格式数据。</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">return</span><span class="code-snippet__plaintext">self 对 result 执行解析票务信息的行为。</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">except</span><span class="code-snippet__plaintext"> Exception </span><span class="code-snippet__keyword">as</span><span class="code-snippet__plaintext"> e:</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">return</span><span class="code-snippet__plaintext"> </span><span class="code-snippet__string"><span class="code-snippet__plaintext">f"查询失败:</span></span><span class="code-snippet__string"><span class="code-snippet__subst"><span class="code-snippet__plaintext">{</span></span></span><span class="code-snippet__string"><span class="code-snippet__subst"><span class="code-snippet__built_in">str</span></span></span><span class="code-snippet__string"><span class="code-snippet__subst"><span class="code-snippet__plaintext">(e)}</span></span></span><span class="code-snippet__string"><span class="code-snippet__plaintext">"</span></span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">def</span><span class="code-snippet__plaintext"> </span><span class="code-snippet__title">_parse_ticket_info</span><span class="code-snippet__plaintext">(</span><span class="code-snippet__params">self, result</span><span class="code-snippet__plaintext">):</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__string">"""解析车票信息"""</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">if</span><span class="code-snippet__plaintext"> </span><span class="code-snippet__string">'data'</span><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">not</span><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">in</span><span class="code-snippet__plaintext"> result </span><span class="code-snippet__keyword">or</span><span class="code-snippet__plaintext"> </span><span class="code-snippet__string">'result'</span><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">not</span><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">in</span><span class="code-snippet__plaintext"> result[</span><span class="code-snippet__string">'data'</span><span class="code-snippet__plaintext">]:</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">return</span><span class="code-snippet__plaintext"> </span><span class="code-snippet__string">"未找到相关车次信息"</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> table = PrettyTable()</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> table.field_names = [</span><span class="code-snippet__string">"车次"</span><span class="code-snippet__plaintext">, </span><span class="code-snippet__string">"出发/到达"</span><span class="code-snippet__plaintext">, </span><span class="code-snippet__string">"历时"</span><span class="code-snippet__plaintext">, </span><span class="code-snippet__string">"商务座"</span><span class="code-snippet__plaintext">, </span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__string">"一等座"</span><span class="code-snippet__plaintext">, </span><span class="code-snippet__string">"二等座"</span><span class="code-snippet__plaintext">, </span><span class="code-snippet__string">"软卧"</span><span class="code-snippet__plaintext">, </span><span class="code-snippet__string">"硬卧"</span><span class="code-snippet__plaintext">, </span><span class="code-snippet__string">"硬座"</span><span class="code-snippet__plaintext">]</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">for</span><span class="code-snippet__plaintext"> item </span><span class="code-snippet__keyword">in</span><span class="code-snippet__plaintext"> result[</span><span class="code-snippet__string">'data'</span><span class="code-snippet__plaintext">][</span><span class="code-snippet__string">'result'</span><span class="code-snippet__plaintext">]:</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">try</span><span class="code-snippet__plaintext">:</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">info 是通过对 item 进行 split 操作得到的。</span><span class="code-snippet__string">'|'</span><span class="code-snippet__plaintext">)</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">train_no 等于 info 中的某个值。</span><span class="code-snippet__number">3</span><span class="code-snippet__plaintext">]</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">from_time 等于 info 中的某个值。具体而言,from_time 是 info 所包含的一个元素。它可能是 info 数组中的一个特定项,或者是 info 对象中的一个属性值。总之,from_time 与 info 存在着特定的关联,其值来自 info。</span><span class="code-snippet__number">8</span><span class="code-snippet__plaintext">]</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">to_time 等于 info 中的某个元素。</span><span class="code-snippet__number">9</span><span class="code-snippet__plaintext">]</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">duration 等于 info 中的某个值。</span><span class="code-snippet__number">10</span><span class="code-snippet__plaintext">]</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">business_seat 等于 info 中的某个元素。</span><span class="code-snippet__number">32</span><span class="code-snippet__plaintext">] </span><span class="code-snippet__keyword">or</span><span class="code-snippet__plaintext"> </span><span class="code-snippet__string">'--'</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">first_seat 等于 info 中的某个元素。具体而言,它是 info 里特定位置或特定条件下所对应的那个值。它可能是 info 数组中的第一个元素,也可能是满足特定规则的那个元素,总之它与 info 存在着特定的关联,代表着 info 所包含的某种信息或数据。</span><span class="code-snippet__number">31</span><span class="code-snippet__plaintext">] </span><span class="code-snippet__keyword">or</span><span class="code-snippet__plaintext"> </span><span class="code-snippet__string">'--'</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">second_seat 等于 info 中的某个元素。具体来说,它是 info 数组或对象中特定位置或条件下所对应的那个值。</span><span class="code-snippet__number">30</span><span class="code-snippet__plaintext">] </span><span class="code-snippet__keyword">or</span><span class="code-snippet__plaintext"> </span><span class="code-snippet__string">'--'</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">soft_sleep 等于 info 中的某个元素。</span><span class="code-snippet__number">23</span><span class="code-snippet__plaintext">] </span><span class="code-snippet__keyword">or</span><span class="code-snippet__plaintext"> </span><span class="code-snippet__string">'--'</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">hard_sleep 等于 info 中的某个内容。具体而言,它可能是 info 所包含的特定数据、属性或元素等,需要根据具体的上下文来确定其确切含义。</span><span class="code-snippet__number">28</span><span class="code-snippet__plaintext">] </span><span class="code-snippet__keyword">or</span><span class="code-snippet__plaintext"> </span><span class="code-snippet__string">'--'</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">hard_seat 等于 info 中的某个元素。</span><span class="code-snippet__number">29</span><span class="code-snippet__plaintext">] </span><span class="code-snippet__keyword">or</span><span class="code-snippet__plaintext"> </span><span class="code-snippet__string">'--'</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">table 添加了一行数据,这行数据的内容为[具体内容]。</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">train_no 表示列车编号,它在铁路运输等领域中具有重要作用,能够用于识别和区分不同的列车。通过 train_no 可以准确地追踪和管理列车的运行情况,包括列车的出发地、目的地、车次等信息。它是铁路系统中不可或缺的一部分,为铁路运输的高效运作提供了基础保障。</span><span class="code-snippet__string"><span class="code-snippet__plaintext">f"</span></span><span class="code-snippet__string"><span class="code-snippet__subst">{from_time}</span></span><span class="code-snippet__string"><span class="code-snippet__plaintext">/</span></span><span class="code-snippet__string"><span class="code-snippet__subst">{to_time}</span></span><span class="code-snippet__string"><span class="code-snippet__plaintext">"</span></span><span class="code-snippet__plaintext">, duration,</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">商务舱座位、头等舱座位、二等舱座位。</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">soft_sleep 、 hard_sleep 以及 hard_seat 。</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> ])</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">except</span><span class="code-snippet__plaintext"> IndexError:</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">continue</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__keyword">return</span><span class="code-snippet__plaintext"> table</span></span></code><code><span leaf=""><span class="code-snippet__keyword">def</span><span class="code-snippet__plaintext"> </span><span class="code-snippet__title">main</span><span class="code-snippet__plaintext">():</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> query = TrainQuery()</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> </span><span class="code-snippet__comment"># 输入查询信息</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">输入的是出发站,该出发站由 input("请输入出发站:")获取。</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">输入到达站的内容为 to_station,即需要输入到达站的相关信息。</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">输入的是出发日期,格式要求为 2024-01-19,该输入通过 input 函数获取并赋值给 date 变量。</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> # 执行查询</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">result 等于通过 query.query_tickets 函数传入 from_station、to_station 和 date 这三个参数所得到的结果。</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> print("\n查询结果:")</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> print(result)</span></span></code><code><span leaf=""><span class="code-snippet__plaintext">if __name__ == '__main__':</span></span></code><code><span leaf=""><span class="code-snippet__plaintext"> main()</span></span></code></pre></p>
代码解析
1. 类的初始化
类初始化时会创建一个会话对象,接着会设置请求头,然后会加载站点数据。通过这样的方式,可以保持连接的持久性,进而提高查询效率。
2. 站点数据加载
方法的作用是从本地文件把车站编码数据加载过来。这些被加载的数据会被用来把车站名称转化为 12306 系统所使用的编码。
3. 车票查询
https://img0.baidu.com/it/u=920932648,1380151833&fm=253&fmt=JPEG&app=138&f=JPEG?w=1031&h=500
方法是具有核心功能的。它会接收出发站、到达站以及日期这些参数。接着构造出请求的 URL。之后再发送 HTTP 请求以获取数据。
4. 数据解析
方法的作用是解析返回的 JSON 数据,并且利用库把结果转化为表格形式,这样便于查看。
使用说明
确保已安装所需的包
运行程序后,按提示输入出发站、到达站和日期
程序会显示符合条件的车次信息,包括车次号、时间、余票等信息
总结
通过这个项目,我们实现了一个实用的火车票查询工具。同时,我们还学习了以下这些知识点:
页:
[1]