抓取ajax动态网页java(如何抓取网页特定数据的爬虫,我是怎么做到的)
优采云 发布时间: 2022-03-05 01:04抓取ajax动态网页java(如何抓取网页特定数据的爬虫,我是怎么做到的)
最近有朋友让我帮我设计一个爬虫,可以爬取网页上的特定数据。我以为这种程序实现起来很简单,只要通过对应的url获取html页面代码,然后解析html得到需要的数据。
但在实践中,我发现我想的太简单了。页面上有很多数据不能简单的从html源码中抓取,因为页面上显示的很多数据其实是在js代码运行时通过ajax从远程服务器获取的。正在加载页面,因此仅仅通过阅读html源代码无法获得所需的数据。
举个例子,我们打开京东首页,在搜索框输入关键词“乌鸡白凤丸”,返回页面显示60个商品,如下图:
打开js控制台,选择element,然后点击左上角的箭头,然后将箭头移到item item,我们可以在html中看到它对应的元素:
我们可以看到页面显示的item对应了id为“gl-i-wrap”的div控件,也就是说如果我们要从html中抓取页面显示的信息,就必须从给定的id中获取html代码div组件然后分析里面的内容,问题是如果你用右键调出他页面的源代码,然后查找字符串“gl-i-wrap”,你会发现它只收录30个,但页面上显示的产品数量是计算出来的。60,也就是30个产品信息不能直接通过html代码获取。
额外的30条信息实际上是在一定条件下触发一段js代码后通过ajax从服务端获取然后添加到DOM中的,所以我们不能简单的从页面对应的html中获取。我通过网上搜索发现对应的解决方法是分析是哪一段js代码负责获取这些数据,然后通过类似于逆向工程的方法研究它是如何构造http请求的,然后模拟发送这些请求获取数据.
我认为这种方法存在一系列问题。首先,要分析很多难读的js代码,工作量和难度可想而知。其次,如果以后这种方式发生变化网站数据采集方式,那么就得再次逆向工程,所以这种方式不经济。
我们怎样才能轻松便捷地获取动态加载的数据呢?
只要在页面上展示商品信息,就可以通过DOM获取,所以如果我们有办法获取浏览器内部的DOM模型,就可以读取动态加载的数据,因为冗余数据触发后页面被下拉。js代码是通过ajax动态获取的,所以如果我们可以通过代码控制浏览器加载网页,然后让浏览器拉下页面,然后读取浏览器页面对应的DOM,就可以获取到动态加载的数据。
经过一番调查,我们发现一个叫selenium的控件可以通过代码来动态控制浏览器,比如让浏览器加载一个特定的页面,让浏览器下拉页面,然后在浏览器,所以我们可以用它来方便的抓取动态页面数据。
首先通过命令pip install selenium下载控件,如果我们要使用它来控制chrome浏览器,我们还需要下载chromedriver控件,首先确定你使用的chrome版本,chromedriver必须和chrome完全一样您当前使用的版本,请从以下链接下载:
请记住选择与您的 chrome 浏览器相同的版本进行下载。完成后,我们可以通过以下代码启动浏览器并使用给定的 URL 加载网页:
op = webdriver.ChromeOptions()
webdriver.Chrome('/Users/apple/Documents/chromedriver/chromedriver', chrome_options = op)
driver.get('#x27;)
运行上述代码后,可以启动浏览器,看到他打开了京东首页。这时候我想在搜索框中自动输入关键词。因此,我们可以使用下面的代码,通过模拟人工输入,在搜索框中输入关键词,然后模拟点击回车键,实现搜索请求:
search_box = driver.find_element_by_id('key')
search_box.send_keys(字)
search_box.send_keys(Keys.ENTER)
超时 = 10
尝试:
print("等待页面...")
WebDriverWait(驱动程序,超时)
除了超时异常:
print("等待页面加载超时")
最后:
.
.
.
.
由于浏览器和我们的代码不再运行在同一个进程中,我们需要调用 WebDriverWait 等待一段时间让浏览器完全加载页面。接下来,为了触发特定的Js代码获取动态加载的数据,我们需要模拟一个人拉下页面。行动:
SCROLL_PAUSE_TIME = 0.5
last_height = driver.execute_script("返回 document.body.scrollHeight")
while True: #将页面滑到底部
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(SCROLL_PAUSE_TIME)
new_height = driver.execute_script("返回 document.body.scrollHeight")
如果 new_height == last_height:
休息
last_height = new_height
上面的代码执行完后,你会发现浏览器页面自动下拉到了底部,所以js会向服务器发送ajax请求获取另外30项的数据,然后我们得到对应的html源码通过执行一段js代码到body组件,然后获取到id为gl-i-wrap的div对象,你会看到它返回了60个对应的组件,也就是说可以获取到页面上的所有商品数据:
page_source = driver.execute_script("返回 document.body.innerHTML;")
bs = BeautifulSoup(page_source, 'html.parser')
info_divs = bs.find_all("div", {"class" : "gl-i-wrap"})
print(len(info_divs)) #这里的输出是60
这样我们就可以读取所有页面显示的商品价格信息。这种方法比解析js代码然后逆向构造http请求获取页面上动态加载的数据要简单、方便、省事得多。更详细的讲解和调试演示请点击“阅读原文”观看视频