整个程序的核心难点在于上次豆瓣爬虫针对的是静态网页,源代码和检查元素内容相同;而在12306的查找搜索过程中,其网页发生变化(出现了查找到的数据),这个过程是动态的,使得我们在审查元素中能一一对应看到的表格数据没有显示在源代码中。这也是这次12306爬虫和上次豆瓣书单爬虫的最大不同点。

查找相关资料,我选择使用Selenium的PhantomJS模拟浏览器爬取源代码,这样获取到的datas包含了我需要的(查找搜索出的)途径站数据。

暂时把整个程序分为了这几个部分:(1)提取列车Code和No信息;(2)找到url规律,根据Code和No变化实现多个网页数据爬取;(3)使用PhantomJS模拟浏览器爬取源代码;(3)用bs4解析源代码,获取所需的途径站数据;(4)用csv库存储获得的数据。

整体使用面向过程的书写方式。

(1)values_get()函数实现了从已有存储了列车信息的csv中逐次提取Code和No。(在这里有点刻意追求面向过程的函数,设置了每次提取都openfile再close。所以使用了tell一次readline完的游标位置,再seek次游标位置到下一次提取位置,实现关闭file后仍然可以接着上一次结束的seek位置继续操作)

(2)olddriver()函数包含PhantomJS和bs4两个部分。利用format来控制多个url,用PhantomJS、driver代替requests爬取网页源代码driver.get(url)。service_args可以配置模拟浏览器(优化加速),set_page_load_timeout()和set_script_timeout()+try except('window.stop()')设置超时(还未用上,存疑),最后用driver.quit()关闭使用完的PhantomJS避免内存爆炸。*这里存在很多优化模拟浏览器的方法,除了上述的配置、超时、quit,还包括在循环外提前打开PhantomJS来实现程序运行时间加速等方法,笔者还未理解透这些方法。这里贴出优化的参考链接:①https://blog.csdn.net/weixin_40284075/article/details/87190040https://www.jianshu.com/p/8ec70859ae03还有PhantomJS的使用攻略①https://www.cnblogs.com/miqi1992/p/8093958.htmlhttps://www.cnblogs.com/lizm166/p/8360388.html

为什么使用已经被Selenium抛弃的PhantomJS而不使用Headless Chrome?笔者也曾尝试过使用无头chrome,但爬到的源代码仍不包含我所需tbody数据。

丢失数据的源代码长这样(它只有tbody标签,没有标签内的数据)。

而检查元素里可以看到所需数据出现在tbody内:

虽然用PhantomJS确实可以爬取到所需的tbody数据,但是在后来循环url爬取多个列车信息时,可能是因为网站有反爬虫措施,或是PhantomJS的不稳定,导致了经常会出现丢失数据的情况(PhantomJS的作用失效了)。所以我添加了一句if datas==[],递归olddriver()来确保能爬到这班列车的信息。如图,失败率仍然很高。

(3)最后是data_write_csv()写入数据到csv,这里用csv库直接把列表变为了csv文件(列表中的多个列表就是多行数据),以后多尝试用一下csv库,还是很好用的。

(4)在主程序调用各个函数时,要注意global全局变量的使用、函数return参数给其他函数使用。

(5)最后是几点自己的建议和猜想。首先如果12306真的有反爬虫,我们可以尝试像requests一样的伪装(在driver里没刻意伪装)或是换其他的网站来爬取。其次多注意:爬取网页查询搜索数据的方法,网页跳转等(或简易成爬取多个网页数据,如本例)。还有PhantomJS和headless Chrome,按理来说headless Chrome不会出现这样的错误。最后是提升爬虫运行速度的方法,(这次的爬取速度实在太慢了,10条信息平均要3分钟才能成功获得),除了对模拟浏览器的配置和优化,以及代码本身的优化(如file文件一直开着,不提取一次数据就开关file一次),我们是否可以尝试其他的源代码.get(url)获取方式?尝试多线程加速?尝试云服务器?

上代码↓

 import urllib3
#import requests
from selenium import webdriver
from bs4 import BeautifulSoup
import csv
import time start = time.time() def values_get():#通过设置游标来实现:从上一次结束的地方继续读取
file = open('Code.csv','r')
global seekloc#全局游标
file.seek(seekloc)#设置游标位置
line = file.readline()
'''
if line == '':
break
'''
if line == '':
seekloc = -1
twovalue = line.strip('\n').split(',')#csv转化为list
code, no = twovalue[0], twovalue[1]
seekloc = file.tell()#读取结束时游标的位置
file.close()
return code, no#code是列车号,no是长串 def olddriver(): #下文中将PhantomJS移除循环未果,任选择在循环中打开。
service_args=[]#PhantomJS优化
service_args.append('--load-images=no') ##关闭图片加载
driver = webdriver.PhantomJS(service_args=service_args) driver.set_page_load_timeout(10) # 设置页面加载超时
driver.set_script_timeout(10) # 设置页面异步js执行超时 url = f'https://kyfw.12306.cn/otn/queryTrainInfo/init?train_no={no}&station_train_code={code}&date=2019-07-16'
try:
driver.get(url)
data = driver.page_source
except:
print('Timeout!')
driver.execute_script('window.stop()')
driver.quit()#这句可让PhantomJS关闭
#return data #def beauti4soup():
#global data
soup = BeautifulSoup(data,'lxml')
table_datas = soup.find('table',{'id':'queryTable'})
datas = table_datas.findAll('tbody')[1].findAll('tr')
if datas == []:
print('Failed... Restart!')
olddriver()
#beauti4soup()
else:
print("It's OK! ")
midways = []
for data in datas:
midway = data.find('div',{'class':'t-station'}).get_text()#单个列车的信息爬取
midways.append(midway)
answer.append(midways)
return answer def data_write_csv(file_name,datas):
file_csv = open(file_name,'w+')
#writer = csv.writer(file_csv,delimiter=',',quotechar=' ',quoting=csv.QUOTE_MINIMAL)csv库用法存疑
writer = csv.writer(file_csv)
for data in datas:
writer.writerow(data) #---主程序开始---# seekloc = 0#初始化游标
values_get()#运行一次values_get()把csv无用的第一行过滤掉
answer = []#存储所有途径站信息的list
'''
#这里三行尝试将PhantomJS放在循环外,提前开启,减少加载时间。
#结果:运行时间确实大幅减短,但遇到一次failed之后就一直failed。
#参考链接:https://blog.csdn.net/qingwuh/article/details/81583801
service_args=[]#PhantomJS优化
service_args.append('--load-images=no') ##关闭图片加载
driver = webdriver.PhantomJS(service_args=service_args)
'''
j = 1
while True:#循环爬取
code, no = values_get()
if j > 10:#十个一循环的测试
break
#if seekloc == -1:
# break
answer = olddriver()
j += 1 data_write_csv('Route.csv',answer)#存储数据 #---主程序结束---#
end = time.time()
print('Running time: {} Seconds'.format(end-start))
print("=================================")

针对源代码和检查元素不一致的网页爬虫——利用Selenium、PhantomJS、bs4爬取12306的列车途径站信息的更多相关文章

  1. Python爬虫初探 - selenium+beautifulsoup4+chromedriver爬取需要登录的网页信息

    目标 之前的自动答复机器人需要从一个内部网页上获取的消息用于回复一些问题,但是没有对应的查询api,于是想到了用脚本模拟浏览器访问网站爬取内容返回给用户.详细介绍了第一次探索python爬虫的坑. 准 ...

  2. selenuim和phantonJs处理网页动态加载数据的爬取

    一.图片懒加载 什么是图片懒加载? 案例分析:抓取站长素材http://sc.chinaz.com/中的图片数据 #!/usr/bin/env python # -*- coding:utf-8 -* ...

  3. 爬虫开发6.selenuim和phantonJs处理网页动态加载数据的爬取

    selenuim和phantonJs处理网页动态加载数据的爬取阅读量: 1203 动态数据加载处理 一.图片懒加载 什么是图片懒加载? 案例分析:抓取站长素材http://sc.chinaz.com/ ...

  4. 6-----selenuim和phantonJs处理网页动态加载数据的爬取

    动态数据加载处理 一.图片懒加载 什么是图片懒加载? 案例分析:抓取站长素材http://sc.chinaz.com/中的图片数据 #!/usr/bin/env python # -*- coding ...

  5. Python爬虫学习三------requests+BeautifulSoup爬取简单网页

    第一次第一次用MarkDown来写博客,先试试效果吧! 昨天2018俄罗斯世界杯拉开了大幕,作为一个伪球迷,当然也得为世界杯做出一点贡献啦. 于是今天就编写了一个爬虫程序将腾讯新闻下世界杯专题的相关新 ...

  6. Python网页解析库:用requests-html爬取网页

    Python网页解析库:用requests-html爬取网页 1. 开始 Python 中可以进行网页解析的库有很多,常见的有 BeautifulSoup 和 lxml 等.在网上玩爬虫的文章通常都是 ...

  7. (五)selenuim和phantonJs处理网页动态加载数据的爬取

    selenuim和phantonJs处理网页动态加载数据的爬取 一 图片懒加载 自己理解------就是在打开一个页面的时候,图片数量特别多,图片加载会增加服务器的压力,所以我们在这个时候,就会用到- ...

  8. 爬虫-----selenium模块自动爬取网页资源

    selenium介绍与使用 1 selenium介绍 什么是selenium?selenium是Python的一个第三方库,对外提供的接口可以操作浏览器,然后让浏览器完成自动化的操作.     sel ...

  9. Python3爬取起猫眼电影实时票房信息,解决文字反爬~~~附源代码

    上文解决了起点中文网部分数字反爬的信息,详细链接https://www.cnblogs.com/aby321/p/10214123.html 本文研究另一种文字反爬的机制——猫眼电影实时票房反爬 虽然 ...

随机推荐

  1. vue+ typescript 使用parcel 构建

    parcel 是一个零配置的前端构建工具,相比webpack 更快,同时使用简单以下是 一个简单的使用typescript 开发vue 应用,同时使用parcel 构建,同时集成了docker 构建, ...

  2. ISE 14.7安装教程最新版(Win10安装)

    一.下载 第一步下载首先自己下载好四个压缩包,把第一个解压,其余的三个不用解压,然后去第一个解压后的文件夹打开启动程序. 第二步是点击启动程序后会有以下界面 next到下一个界面,这个时候需要把之前没 ...

  3. python总结四

    sql性能优化的几种方式: 1.查询的模糊匹配: 尽量避免在一个复杂查询里面使用like '%parm%',前面的%会导致相关列的索引无法使用,最好不要用 直接修改后台,根据输入条件,先查出符合条件的 ...

  4. HashMap源码2

    public class test { @SuppressWarnings({ "rawtypes", "unchecked" }) public static ...

  5. Linux驱动架构之pinctrl子系统分析(一)

    1.前言在嵌入式系统中,许多SoC的内部都包含了pin控制器,通过芯片内部的pin控制器,我们可以配置一个或者一组引脚的状态和功能特性,Linux内核为了统一各SoC厂商的引脚管理,提供了pinctr ...

  6. FusionInsight大数据开发---Oozie应用开发

    Oozie应用开发 要求: 了解Oozie应用开发适用场景 掌握Oozie应用开发 熟悉并使用Oozie常用API Oozie简介 Oozie是一个Hadoop作业的工作流调度管理系统 Oozie工作 ...

  7. 前端开发神一样的工具chrome调试技巧

    前端开发神一样的工具chrome调试技巧 文章来自  Colin-UED // 与您分享前端开发知识 主页 Javascript HTML CSS NodeJs User Experience FE ...

  8. cygwin中修改path变量

    1.在家目录建立 .bash_profile 文件. 2.在该文件添加: export PATH=/my/path/:$PATH 3.解释,/my/path/为你要添加的目录,为什么不在.bashrc ...

  9. C# zip压缩 Ionic.Zip.dll

    #region Ionic.Zip压缩文件 //压缩方法一 public void ExeCompOne() { string FileName = DateTime.Now.ToString(&qu ...

  10. Git 解决合并分支时的冲突

    参考链接:https://www.liaoxuefeng.com/wiki/896043488029600/900004111093344 创建分支时,新分支的文件内容建立在原分支的基础上,我们称这时 ...