爬取msdn.itellyou.cn网站
最近一直在琢磨爬虫,从最早的BeautifulSoup爬取游民福利图,后来要爬取的动态网页多了,就逐渐过渡到了selenium+chromedriver/phantomJs的爬虫组合。偶然间听基友说有个msdn.itellyou.cn里收集了各种微软程序的ed2k安装包,因此便开始了对它的爬取之旅。这个网站的页面结构还是挺复杂的。通过观察,发现软件的名称和地址都在右侧内容项中的label>ch
最近一直在琢磨爬虫,从最早的BeautifulSoup爬取游民福利图,后来要爬取的动态网页多了,就逐渐过渡到了selenium+chromedriver/phantomJs的爬虫组合。偶然间听基友说有个msdn.itellyou.cn里收集了各种微软程序的ed2k安装包,因此便开始了对它的爬取之旅。
这个网站的页面结构还是挺复杂的。通过观察,发现软件的名称和地址都在右侧内容项中的label>checkbox中,名称为label的值,而地址为checkbox的data-url属性。且右侧的具体内容是通过div的动态加载来实现的,只有在点击了左侧的具体目录项才会出现;对于多语言的软件,每个子标签中的软件的xpath中的id又是不同的,因此需要动态获得每个子标签的id。最后,该网站会时不时地弹出呼吁捐赠的对话框,也会对爬虫造成影响。
由于采用selenium+chromedriver,且网站的各个资源项的id也摸不到规律,只能用最笨的方法——模拟点击法来获取所有软件的地址,即将目录项一个一个点开后再依次点击右侧的语言栏(若有的话);同时,在点击时还要处理随时可能弹出的捐款对话框。此外,有很多目录项里头其实没有数据,但也要花费一定时间点击。总的来说,这个爬虫效率是比较低的,若大家有更高效率的方法,欢迎提出。
源代码如下:
# -*- coding=utf-8 -*-
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
import time
from selenium.common.exceptions import NoSuchElementException,ElementNotVisibleException,WebDriverException,TimeoutException
import xlwt
#左侧目录的xpath
catalogue_list = ['//*[@id="accordion"]/div[1]/div[1]/h4/a',
'//*[@id="accordion"]/div[2]/div[1]/h4/a',
'//*[@id="accordion"]/div[3]/div[1]/h4/a',
'//*[@id="accordion"]/div[4]/div[1]/h4/a',
'//*[@id="accordion"]/div[5]/div[1]/h4/a',
'//*[@id="accordion"]/div[6]/div[1]/h4/a',
'//*[@id="accordion"]/div[7]/div[1]/h4/a',
'//*[@id="accordion"]/div[8]/div[1]/h4/a'
]
catalogue_name = [u'企业解决方案',
u'MSDN技术资源库',
u'工具和资源',
u'应用程序',
u'开发人员工具',
u'操作系统',
u'服务器',
u'设计人员工具'
]
count = 0
software_name_list = []
software_url_list = []
def builddriver(kind):
chromedriver_path = 'D:\\WebDrivers\\chromedriver_win32\\chromedriver.exe'
phantomjs_path = 'D:\\WebDrivers\\phantomjs\\bin\\phantomjs.exe'
if kind == 'Chrome':
driver = webdriver.Chrome(executable_path=chromedriver_path)
elif kind == 'Phantomjs':
driver = webdriver.PhantomJS(executable_path=phantomjs_path)
return driver
#关闭弹出的捐款对话框
def clickdialog():
global driver
try:
dialog_close_button = driver.find_element_by_xpath('/html/body/div[2]/div/div/div[1]/button')
if dialog_close_button:
dialog_close_button.click()
time.sleep(3)
except NoSuchElementException:
pass
except ElementNotVisibleException:
pass
#通过该函数调用所有的点击功能,防止对话框干扰
def click_when_dialog(target_item):
try:
target_item.click()
except WebDriverException:
clickdialog()
target_item.click()
except NoSuchElementException, e:
raise e
except TimeoutException:
time.sleep(2)
target_item.click()
# 处理某灵异bug……
except WebDriverException:
time.sleep(2)
target_item.click()
finally:
time.sleep(4)
def get_one_kind_software(kind_name_selector, type_name):
global software_name_list, software_url_list
software_file = open(type_name + '.txt', 'w')
kind_name = driver.find_element_by_xpath(kind_name_selector)
click_when_dialog(kind_name)
kind_id = kind_name.get_attribute('data-target')[1:]
software_item = driver.find_elements_by_xpath('//*[@id="' + kind_id + '"]/div/ul/li') # 目录下的软件列表项
# 顺序点击每个目录项
for i in range(0, len(software_item)):
click_when_dialog(software_item[i])
# 获取右侧数据
# 多语言:
# 获取多语言列表
multi_languate_list = driver.find_elements_by_xpath('//*[@id="view_data_container"]/ul/li/a')
if multi_languate_list:
for j in range(0, len(multi_languate_list) - 1):
software_id = 'lang_' + multi_languate_list[j].get_attribute('data-id')
try:
click_when_dialog(multi_languate_list[j])
except NoSuchElementException:
continue
# 获取具体内容
try:
software_name = driver.find_element_by_xpath('//*[@id="' + software_id + '"]/ul/li/div/label').text
software_url = driver.find_element_by_xpath(
'//*[@id="' + software_id + '"]/ul/li/div/label/input').get_attribute('data-url')
except NoSuchElementException:
# 可能未加载完,但实际有
time.sleep(4)
try:
software_name = driver.find_element_by_xpath(
'//*[@id="' + software_id + '"]/ul/li/div/label').text
software_url = driver.find_element_by_xpath(
'//*[@id="' + software_id + '"]/ul/li/div/label/input').get_attribute('data-url')
# 这个真没有……
except NoSuchElementException:
continue
software_name_list.append(software_name)
software_url_list.append(software_url)
for i in range(0, len(software_name_list)):
software_file.write(software_name_list[i] + ' ' + software_url_list[i] + '\n')
print type_name + '已爬取完成。\n'
# 清空已写入至文件的列表
software_name_list = []
software_url_list = []
software_file.close()
def file_to_excel():
global count
workbook = xlwt.Workbook()
sheet_list = []
for sheet_name in catalogue_name:
sheet = workbook.add_sheet(unicode(sheet_name), cell_overwrite_ok=True)
sheet_list.append(sheet)
# 依次打开文件并写入对应的sheet
for i in range(0, len(catalogue_name)):
count = 0
software_file = open(unicode(catalogue_name[i]) + '.txt', 'r')
for line in software_file:
sheet_list[i].write(count, 0, unicode(line.split(' ')[0]))
sheet_list[i].write(count, 1, unicode(line.split(' ')[1]))
count += 1
software_file.close()
print u'软件存储完成'
workbook.save('software.xls')
driver = builddriver('Chrome')
if __name__ == "__main__":
global driver
driver.get('http://msdn.itellyou.cn/')
time.sleep(5)
for k in range(0, len(catalogue_list)):
get_one_kind_software(catalogue_list[k], catalogue_name[k])
driver.close()
file_to_excel()
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">此网站共分为8个目录,这段程序将每个目录的结果分别存为一个txt文件,最后再将其整理成一个excel文件。</span>
代码中的所谓“灵异bug”,是指在爬取操作系统那一目录时,经常到MS-DOS西班牙语之后会弹出异常:Other element would receive click:<nav class="balabala ……></nav>,且有时出现在这里,有时出现在爬取完Win7处,单步也抓不到。因此只能抛出一个WebdDriverException,处理方法是等2s后再试一次。
爬取后的成果:
个人感觉,用selenium+chromedriver/phantomjs爬取网页的效率实在是不高,但是碰到动态网页似乎又没有其他更好的办法。若有高人知道高效爬取动态网页的方法,还请不吝赐教。
更多推荐
所有评论(0)