一,尝试用BeautifulSoup抓取
先打开KFC网站门店列表页面:http://www.kfc.com.cn/kfccda/storelist/index.aspx
可以看到门店列表如下图:
打开Chrome Developer Tools观察页面结构,找到标签如下:
发现要的数据位于id='listhtml'的表里,门店地址数据位于第二个tr开始的行里,尝试用bs抓取:
url = 'http://www.kfc.com.cn/kfccda/storelist/index.aspx' html = urllib.urlopen(url).read().decode('utf-8') bsObj = BeautifulSoup(html, "html.parser") print bsObj.find('tbody', {'id':'listhtml'})
输出:
<tbody id="listhtml"> </tbody>
表格不包含任何内容,可见数据由ajax动态生成,抓取失败。
二,用selenium + PhantomJS抓取
url = 'http://www.kfc.com.cn/kfccda/storelist/index.aspx' # html = urllib.urlopen(url).read().decode('utf-8') # bsObj = BeautifulSoup(html, "html.parser") # print bsObj.find('tbody', {'id':'listhtml'}) driver = webdriver.PhantomJS(executable_path='/home/guowei/bin/phantomjs/bin/phantomjs') driver.get(url) print driver.find_element_by_id('listhtml')
输出结果:
<selenium.webdriver.remote.webelement.WebElement object at 0xb6823a8c>
有抓取到对象,但不能确定是否是包含需要的数据,再分析网页结构,抓出第一家门店地址看看:
print driver.find_element_by_id('listhtml').find_element_by_xpath('//tr[2]/td[1]').text
输出结果:
茂名餐厅
说明已经成功抓取动态网页的数据!
三、抓取KFC门店数据
观察门店数据表格,所需数据从第二行开始,每行前2列表格数据有用,因此抓取代码如下:
#!/usr/bin/env python # -*- coding: utf-8 -*- from selenium import webdriver import time url = 'http://www.kfc.com.cn/kfccda/storelist/index.aspx' driver = webdriver.PhantomJS(executable_path='/home/guowei/bin/phantomjs/bin/phantomjs') driver.get(url) time.sleep(2) for i in range(1,11): shopName_xpath = '//tr[' + str(i + 1) + ']/td[1]' shopAddress_xpath = '//tr[' + str(i + 1) + ']/td[2]' shopName = driver.find_element_by_css_selector('#listhtml').find_element_by_xpath(shopName_xpath).text shopAddress = driver.find_element_by_css_selector('#listhtml').find_element_by_xpath(shopAddress_xpath).text print shopName print shopAddress
输出结果:
茂名餐厅 吴江路269号2层 翔川餐厅 妙镜路1118号E号商铺 动力南广场餐厅 石龙路750-3号上海南站地下商场南馆 江苏餐厅 江苏路398号1、2层 威宁餐厅 天山路352号101和201 思贤餐厅 思贤路778--180号 惠乐餐厅 人民西路955号 柳州餐厅 沪闵路9001号上海南站站厅层 真北餐厅 桃浦路328号 马陆弘基餐厅 马陆镇沪宜公路2398/2400号
四、总结
time.sleep()非常重要,如果网速太慢有时候ajax程序还未从服务器取得数据,当然用检测一个特定HTML标签的方式会更高效,比如检测上述数据所在表格最后一行最后一格已经载入就可以开始抓取数据。