目标是抓取所有选项下的表格数据。
目标网址:https://gkcx.eol.cn/school/search
用开发者工具查看表格及选项框的构造:
下拉框是<ul><li>标签组成的,用js实现动态切换,靠selenium很难实现定位和模拟点击。
解决方法:分析页面网络请求流,尝试抓取服务器返回给客户端的数据。
选用方法步骤简述:先打开开发者工具,点击网络,此时点击切换省份,可以查看到请求流,其中类型为html的是我们需要的信息。点击的过程是客户端向服务器发送请求的过程,后面的分数就是服务器收到请求后向客户端返回的数据。
单击查看它的头部信息,消息头里有个请求网址,我们对它进行分析
所以,只需要改变上述几个参数,重构url,就可以通过url获取所有的数据!
我尝试了用requests发送post请求,加上从页面获取的请求头信息,但是服务器应该是识别出了爬虫程序,所以访问没有成功,返回错误码503,最终还是决定用selenium,毕竟Selenium模拟人工很难被识别出来。
双击点开开发者工具中html类型的请求,页面中的数据就是返回的Json数据,下一步就是抓取并解析。
参考代码:
import re from selenium import webdriver f = open("HunanTest.txt", 'r', encoding="utf-8") # 打开抓取的url文件 univs = [] for i in f: # 用正则表达式匹配数字(学校id)存在univs列表中 univid = re.search(r'\d+', i).group() univs.append(univid) browser = webdriver.Firefox() info = [] vacant = [] # 四重for循环用于构建新的Url for univ in univs: for provId in open("prov.txt", 'r', encoding='utf-8'): # 各省份的id for typeId in range(1, 3): # 类别,理科是1,文科是2 for year in range(2016, 2019): # 年份,2016-2018 url = "https://api.eol.cn/gkcx/api/?access_token=&local_province_id=" + str( provId) + "&local_type_id=" \ + str(typeId) + "&school_id=" + str(univ) + "&signsafe=&uri=apidata/api/gk/score/province&year=" \ + str(year) browser.get(url) html = browser.page_source # 正则表达式匹配相关信息 try: name = re.findall(r'"name":"(.+?)",', html) prov = re.findall(r'"local_province_name":"(.+?)",', html) typeNum = re.findall(r'"local_type_name":"(.+?)",', html) average = re.findall(r'"average":"(.+?)",', html) min = re.findall(r'"min":"(.+?)",', html) max = re.findall(r'"max":"(.+?)",', html) proscore = re.findall(r'"proscore":"(.+?)",', html) batch = re.findall(r'"local_batch_name":"(.+?)",', html) # 构建数据字典 data = {"学校名称": name[0], "学校ID": univ, "省份": prov[0], "年份": year, "类别": typeNum[0], "平均分": average[0], "最高分": max[0], "最低分": min[0], "省份批次线": proscore[0], "录取批次": batch[0] } print(data) info.append(data) # 异常处理,很多学校在部分省份的招生信息是缺失的,获取不到信息时,就打印url并存储(暂无他用) except IndexError: print(url) vacant.append(url) browser.close()
结果: