使用Python自动化获取全国每个城市的车牌代码

最近有这样一需求,需要获取12123交管查询网站上的全国每个城市对应的城市id和车牌代码。最初的想法是直接用Python写个爬虫,遍历每个城市,然后用Xpath提取DOM节点数据就好了。然而在实际操作中发现城市id的DOM节点如果用简单的获取网页数据的爬虫是取不到id值的,这个城市id值必须用浏览器打开的方式去访问,然后网站的js脚本再动态的将城市id插入DOM节点。于是乎想到了用自动化测试工具来做,使用selenium库来操作webdriver,驱动Chrome浏览器进行自动化操作。

由于这个网站有一点特殊,并没有在同一个页面中有全部城市的id和车牌代码,每个城市都是一个单独的二级域名链接。并且城市id使用js动态加载,所以这里就用蠢一点的方法,自动获取到每个城市的链接,然后用浏览器自动化模式去逐个访问再Xpath提取出内容。

当然,这里的重复劳动力交给计算机就好,我们只需要把程序写好。

使用Chrome浏览器打开12123的城市列表选择页面 http://m.12123.com/city.html

右键,审查元素,发现所有的城市都在ul 的 li标签下。
只需要把li的元素Xpath拷贝出来,提取到城市列表后遍历每个列表的链接,再用浏览器自动化去访问每个城市的链接,最后用相同的方法提取出数据即可。
拷贝出来的Xpath如下

1
/html/body/div[2]/div[3]/ul/li

用Xpath的方式有个好处就是不需要写复杂的正则表达式就可以快速提取到DOM元素的数据。

我要实现的功能:

  1. 自动获取全国所有的城市对应的id和车牌代码
  2. 将获取到的数据写入到文件,输出为SQL的insert语句

全部代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
"""
12123.com 交管查询助手
获取所有的 城市名称+城市车牌代码+城市id
生成SQL insert语句
create by 蓝士钦 2018-06-10
"""
import requests
from lxml import etree
from selenium import webdriver
import datetime

# 12123.com 交管查询网站移动版网址
HOST_URL = 'http://m.12123.com'


def get_city_info(file_name):
# 请求城市列表页面,并用xpath提取所有的城市列表集合
html = requests.get(HOST_URL + '/city.html')
select = etree.HTML(html.text)
content = select.xpath('/html/body/div[2]/div[3]/ul/li')

# 打开指定文件,准备将请求到的数据写入到文件中
file = open(file_name, 'w')

# 遍历所有的城市列表集合
for index, value in enumerate(content):
# 提取当前城市列表中的a标签的城市链接
item = value.xpath('/html/body/div[2]/div[3]/ul/li[' + str(index) + ']/a/@href')
for city_path in item:
city_url = HOST_URL + city_path
print('当前城市链接:' + city_url)
try:
# 打开Chrome浏览器,自动化访问城市链接
browser = webdriver.Chrome()
browser.get(url=city_url)
# 提取城市名称、城市车牌代码、城市id
city_name = browser.find_element_by_xpath('/html/body/div[4]/div[1]/a/span').text
car_num_pre = browser.find_element_by_xpath('//*[@id="txtAbbr"]').text + browser.find_element_by_xpath(
'//*[@id="txtInitial"]').text
city_id = browser.find_element_by_xpath('//*[@id="cityId"]').get_attribute('value')
print('城市名称:' + city_name + ' 车牌代码:' + car_num_pre + ' 城市id:' + city_id)
# 写入文件
file.writelines("insert into city_info ('city_name','car_num_pre','city_id') "
+ "values ('" + city_name + "','" + car_num_pre + "','" + city_id + "');\n")
# 刷新缓冲区,将缓冲区数据写入文件,防止缓冲区有大量待写入数据时突然断电造成数据丢失
file.flush()
# 关闭浏览器
browser.close()
except:
print('获取城市信息时发生异常')
continue

# 关闭文件流
file.close()


if __name__ == '__main__':
start_time = datetime.datetime.now()
# 获取城市名称、车牌代码、城市id,并写入指定的sql文件中
get_city_info("city_info.sql")
end_time = datetime.datetime.now()
print('总用时:' + str((end_time - start_time).seconds) + '秒')

点击运行之后就可以放心的出去玩了😋

控制台这边对每个链接的访问情况做了输出,如果有异常(网络超时)可以等全部结束后单独把异常的城市再跑一边即可。
最后输出的SQL文件如下图:

注: 使用WebDriver前,需要将对应平台的webdriver驱动复制到系统环境变量中。

0%