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

整个程序的核心难点在于上次豆瓣爬虫针对的是静态网页,源代码和检查元素内容相同;而在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)获取方式?尝试多线程加速?尝试云服务器?

上代码↓

  1 import urllib3
  2 #import requests
  3 from selenium import webdriver
  4 from bs4 import BeautifulSoup
  5 import csv
  6 import time
  7
  8 start = time.time()
  9
 10 def values_get():#通过设置游标来实现:从上一次结束的地方继续读取
 11     file = open(‘Code.csv‘,‘r‘)
 12     global seekloc#全局游标
 13     file.seek(seekloc)#设置游标位置
 14     line = file.readline()
 15     ‘‘‘
 16     if line == ‘‘:
 17         break
 18     ‘‘‘
 19     if line == ‘‘:
 20         seekloc = -1
 21     twovalue = line.strip(‘\n‘).split(‘,‘)#csv转化为list
 22     code, no = twovalue[0], twovalue[1]
 23     seekloc = file.tell()#读取结束时游标的位置
 24     file.close()
 25     return code, no#code是列车号,no是长串
 26
 27 def olddriver():
 28
 29     #下文中将PhantomJS移除循环未果,任选择在循环中打开。
 30     service_args=[]#PhantomJS优化
 31     service_args.append(‘--load-images=no‘)  ##关闭图片加载
 32     driver = webdriver.PhantomJS(service_args=service_args)
 33
 34     driver.set_page_load_timeout(10)  # 设置页面加载超时
 35     driver.set_script_timeout(10)  # 设置页面异步js执行超时
 36
 37     url = f‘https://kyfw.12306.cn/otn/queryTrainInfo/init?train_no={no}&station_train_code={code}&date=2019-07-16‘
 38     try:
 39         driver.get(url)
 40         data = driver.page_source
 41     except:
 42         print(‘Timeout!‘)
 43         driver.execute_script(‘window.stop()‘)
 44     driver.quit()#这句可让PhantomJS关闭
 45     #return data
 46
 47 #def beauti4soup():
 48     #global data
 49     soup = BeautifulSoup(data,‘lxml‘)
 50     table_datas = soup.find(‘table‘,{‘id‘:‘queryTable‘})
 51     datas = table_datas.findAll(‘tbody‘)[1].findAll(‘tr‘)
 52     if datas == []:
 53         print(‘Failed... Restart!‘)
 54         olddriver()
 55         #beauti4soup()
 56     else:
 57         print("It‘s OK! ")
 58     midways = []
 59     for data in datas:
 60         midway = data.find(‘div‘,{‘class‘:‘t-station‘}).get_text()#单个列车的信息爬取
 61         midways.append(midway)
 62     answer.append(midways)
 63     return answer
 64
 65 def data_write_csv(file_name,datas):
 66     file_csv = open(file_name,‘w+‘)
 67     #writer = csv.writer(file_csv,delimiter=‘,‘,quotechar=‘ ‘,quoting=csv.QUOTE_MINIMAL)csv库用法存疑
 68     writer = csv.writer(file_csv)
 69     for data in datas:
 70         writer.writerow(data)
 71
 72
 73 #---主程序开始---#
 74
 75 seekloc = 0#初始化游标
 76 values_get()#运行一次values_get()把csv无用的第一行过滤掉
 77 answer = []#存储所有途径站信息的list
 78 ‘‘‘
 79 #这里三行尝试将PhantomJS放在循环外,提前开启,减少加载时间。
 80 #结果:运行时间确实大幅减短,但遇到一次failed之后就一直failed。
 81 #参考链接:https://blog.csdn.net/qingwuh/article/details/81583801
 82 service_args=[]#PhantomJS优化
 83 service_args.append(‘--load-images=no‘)  ##关闭图片加载
 84 driver = webdriver.PhantomJS(service_args=service_args)
 85 ‘‘‘
 86 j = 1
 87 while True:#循环爬取
 88     code, no = values_get()
 89     if j > 10:#十个一循环的测试
 90         break
 91     #if seekloc == -1:
 92     #    break
 93     answer = olddriver()
 94     j += 1
 95
 96 data_write_csv(‘Route.csv‘,answer)#存储数据
 97
 98 #---主程序结束---#
 99 end = time.time()
100 print(‘Running time: {} Seconds‘.format(end-start))
101 print("=================================")

原文地址:https://www.cnblogs.com/hsh17/p/11105184.html

时间: 2024-08-11 01:35:19

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

想开发网页爬虫,发现被反爬了?想对 App 抓包,发现数据被加密了?不要担心,这里可以为你解决。

全面超越Appium,使用Airtest超快速开发App爬虫 想开发网页爬虫,发现被反爬了?想对 App 抓包,发现数据被加密了?不要担心,使用 Airtest 开发 App 爬虫,只要人眼能看到,你就能抓到,最快只需要2分钟,兼容 Unity3D.Cocos2dx-*.Android 原生 App.iOS App.Windows Mobile……. Airtest是网易开发的手机UI界面自动化测试工具,它原本的目的是通过所见即所得,截图点击等等功能,简化手机App图形界面测试代码编写工作. 安

python网络爬虫之使用scrapy自动爬取多个网页

前面介绍的scrapy爬虫只能爬取单个网页.如果我们想爬取多个网页.比如网上的小说该如何如何操作呢.比如下面的这样的结构.是小说的第一篇.可以点击返回目录还是下一页 对应的网页代码: 我们再看进入后面章节的网页,可以看到增加了上一页 对应的网页代码: 通过对比上面的网页代码可以看到. 上一页,目录,下一页的网页代码都在<div>下的<a>元素的href里面.不同的是第一章只有2个<a>元素,从二章开始就有3个<a>元素.因此我们可以通过<div>

python网络爬虫之scrapy 调试以及爬取网页

Shell调试: 进入项目所在目录,scrapy shell "网址" 如下例中的: scrapy shell http://www.w3school.com.cn/xml/xml_syntax.asp 可以在如下终端界面调用过程代码如下所示: 相关的网页代码: 我们用scrapy来爬取一个具体的网站.以迅读网站为例. 如下是首页的内容,我想要得到文章列表以及对应的作者名称. 首先在items.py中定义title, author. 这里的Test1Item和Django中的modul

python3下scrapy爬虫(第八卷:循环爬取网页多页数据)

之前我们做的数据爬取都是单页的现在我们来讲讲多页的 一般方式有两种目标URL循环抓取 另一种在主页连接上找规律,现在我用的案例网址就是 通过点击下一页的方式获取多页资源 话不多说全在代码里(因为刚才写这篇文章时电脑出现点问题所以没存下来,所以这一版本不会那么详细) 来 看下结果522*35条连接页面的数据爬取: 是不是很爽 原文地址:https://www.cnblogs.com/woshiruge/p/8398229.html

java实现网页爬虫

接着上面一篇对爬虫需要的java知识,这一篇目的就是在于网页爬虫的实现,对数据的获取,以便分析. -----> 目录:   1.爬虫原理 2.本地文件数据提取及分析 3.单网页数据的读取 4.运用正则表达式完成超连接的连接匹配和提取 5.广度优先遍历,多网页的数据爬取 6.多线程的网页爬取 7.总结 爬虫实现原理 网络爬虫基本技术处理 网络爬虫是数据采集的一种方法,实际项目开发中,通过爬虫做数据采集一般只有以下几种情况: 1) 搜索引擎 2) 竞品调研 3) 舆情监控 4) 市场分析 网络爬虫的

[python] 常用正则表达式爬取网页信息及分析HTML标签总结【转】

[python] 常用正则表达式爬取网页信息及分析HTML标签总结 转http://blog.csdn.net/Eastmount/article/details/51082253 标签: pythonpython爬虫正则表达式html知识总结 2016-04-07 06:13 3615人阅读 评论(4) 收藏 举报  分类: Python爬虫(23)  Python基础知识(17)  版权声明:本文为博主原创文章,转载请注明CSDN博客源地址!共同学习,一起进步~ 这篇文章主要是介绍Pytho

Scrapy精华教程(六)——自动爬取网页之II(CrawlSpider)

一.目的. 在教程(二)(http://blog.csdn.net/u012150179/article/details/32911511)中使用基于Spider实现了自己的w3cschool_spider,并在items.py中定义了数据结构, 在pipelines.py中实现获得数据的过滤以及保存. 但是以上述方法只能爬取start_url列表中的网页,而网络爬虫如google等搜索引擎爬虫实现的就是对整个互联网的爬取,所以在本教程中研究使用scrapy自动实现多网页爬取功能. 在教程(五)

Scrapy研究探索(六)——自己主动爬取网页之II(CrawlSpider)

原创,转载注明:http://blog.csdn.net/u012150179/article/details/34913315 一.目的. 在教程(二)(http://blog.csdn.net/u012150179/article/details/32911511)中使用基于Spider实现了自己的w3cschool_spider,并在items.py中定义了数据结构, 在pipelines.py中实现获得数据的过滤以及保存. 可是以上述方法仅仅能爬取start_url列表中的网页.而网络爬

【转】 Scrapy研究探索(六)——自动爬取网页之II(CrawlSpider)

转自http://blog.csdn.net/u012150179/article/details/34913315 一.目的. 在教程(二)(http://blog.csdn.net/u012150179/article/details/32911511)中使用基于Spider实现了自己的w3cschool_spider,并在items.py中定义了数据结构, 在pipelines.py中实现获得数据的过滤以及保存. 但是以上述方法只能爬取start_url列表中的网页,而网络爬虫如googl