selenium+beautifulsoup爬取动态网站

在刚学习爬虫的时候,就听说的过强大的selenium库,但从来没用过,直到遇到了一个动态网站。

网站地址如下:https://www.tran.sla.ny.gov/JSP/query/PublicQueryAdvanceSearchPage.jsp
随意进行zipcode搜索,会得到一张表单结果,点击next按钮进行翻页的时候,可以发现网站的url不会发生任何变化。显然,采用常规的改变url的方式发送post请求,解析html代码的方式行不通。

但是,几乎所有的技术都是存在内在逻辑的,必定存在一个真实的url对应于不同的表单结果,不然电脑怎么知道该显示什么内容?

于是乎又开始琢磨怎么找真实的url,天真的以为,网站会用类似“pagenumber=1”之类的方式对应不同的表单内容。不幸的是,水平有限,没找出来真实的url,隐藏的有点深。【ps:作为一个government的网站,搞这么复杂干嘛!!】

最后走投无路选择了selenium。。。

selenium这个库想法很简单,就是模拟人操作浏览器,比如鼠标点击(click)、输入值(send_keys)、刷新网页(refresh)。那么如何去控制不同的浏览器呢?不同的浏览器(chrome和Firefox)都会提供自己的webdriver,只需要根据浏览器版本安装对应的webdriver插件。windows和linux上将webdriver加入环境变量中,即可被selenium调用。在windows上显示如下内容表示配置成功

Smiley face

有了selenium之后,找什么真实的url都是不存在的,只需要模拟人去点击一下next,然后静静地等待网页加载完成即可获得数据。

数据获取的方式又有两种:1.完全使用selenium去扣取表格内值;2.使用selenium模拟人进行翻页操作,然后获取加载完成的HTML代码,用beautifulsoup进行解析,读取表格内容;

我采用了第二种方式,具体代码如下,用的是Python3

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
63
64
65
66
67
68
69
70
#-*-coding:utf-8 -*-

import re
import selenium
from pandas import DataFrame
from selenium import webdriver
from bs4 import BeautifulSoup

#获取表格的标题
def get_table_title(soup):
table_title = []
for tr in soup.findAll('tr')[0:1]:
for th in tr.findAll('th'):
table_title.append(th.get_text())
return table_title

#获取表格的内容
def get_table_content(soup):
table_content = []
for tr in soup.findAll('tr'):
row_content = []
for td in tr.findAll('td'):
#对去掉多余空格
row_content.append(re.sub("\s+", " ",td.get_text()))
table_content.append(tuple(row_content))
return table_content

#判断页面中是否存在某个元素,这里判断“next button”是否存在
def isElementExist(driver,element):
flag=True
try:
driver.find_element_by_name(element)
return flag
except:
flag=False
return flag

def main():

url = "https://www.tran.sla.ny.gov/JSP/query/PublicQueryAdvanceSearchPage.jsp"
zipcode = "10024"
flag = True

driver = webdriver.Chrome()
#设定隐式等待30s,国外网站加载比较慢,建议使用科学上网工具,否则可能需要换其他的等待方式
driver.implicitly_wait(30)
driver.get(url)
driver.find_element_by_id("zipCode").send_keys(zipcode)
driver.find_element_by_id("searchButton").click()
##等待加载完成

table_html_code = driver.find_element_by_xpath("/html/body/table[1]/tbody/tr[1]/td[2]/table/tbody/tr[2]/td[2]/table[4]/tbody/tr/td/table/tbody/tr/td[2]/form[2]/div[2]/table[1]").get_attribute("innerHTML")
soup = BeautifulSoup(table_html_code,"lxml")
table_title = get_table_title(soup)
table_content = get_table_content(soup)

#进行翻页读取数据
while flag:
driver.find_element_by_name("NextButton").click()
##等待加载完成
table_html_code = driver.find_element_by_xpath("/html/body/table[1]/tbody/tr[1]/td[2]/table/tbody/tr[2]/td[2]/table[4]/tbody/tr/td/table/tbody/tr/td[2]/form[2]/div[2]/table[1]").get_attribute("innerHTML")
soup = BeautifulSoup(table_html_code,"lxml")
table_content.extend(get_table_content(soup))
flag = isElementExist(driver,"NextButton")

data = DataFrame(table_content, columns=table_title)
print(data)

if __name__ == '__main__':
main()

结果示意图
Smiley face
Smiley face