因为在尝试完成一个QA问答对,所以第一阶段的目标是对信息的收集,所以采用了爬虫+python的方式去爬取网站。最终在学习了Scrapy、Webdriver等框架,最终还是采用了最简单的pyquery的css选择器对爬取到的HTML文档进行选择,在这里就介绍爬取百度和百度知道两个实例的过程:
百度首页
百度的源码爬取十分有意思,正常我们的爬取过程都是用Requests库里的get函数,输入需要查询的URL就能获取doc文档里的preview源码,但是百度的源码和我们爬取的代码之间会存在缺失的情况,这是因为部分的百度界面使用AJAX渲染过后的结果,如果直接调用函数是无法得到结果的。所以我们使用webdriver来控制一个浏览器,完成第一步对查询首页源码的获取,代码如下:
> browser =webdriver.Chrome("C:\\Program Files (x86)\\Google\\Chrome\\Application\\chromedriver.exe")
wait=WebDriverWait(browser,10)
def search():
browser.get("https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=fgo&oq=python%2520mongodb%2520%25E5%258E%25BB%25E9%2587%258D&rsv_pq=9a14647300015f34&rsv_t=f8f30Y4s%2BLQUtCWZdlYZngwB1hmtApMGDGRBMtVhF%2FusnOTF7db6eJaB010&rqlang=cn&rsv_enter=0&inputT=10679&rsv_sug3=150&rsv_sug1=108&rsv_sug7=100&bs=python%20mongodb%20%E5%8E%BB%E9%87%8D")
input = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#result_logo > img.index-logo-src')))
html = browser.page_source
这里的html就是我们需要的对应的百度页面的源码,这里webdriver判断是否打开了页面的依据是result-logo对应的图片是否成功加载。
然后在获取到网页的源码之后,可以采取正则,beautifulsoup或者pyquery来进行对应信息的提取,这里我们采用pyquery这种方式来进行信息的采集。首先是对爬取到的html文件进行转换为pyquery格式
doc=pq(html)
然后根据css选择器的规矩进行标签对的选取,这里再介绍一下使用webdriver进行翻页,因为百度的翻页只能通过点击下一页的按钮进行翻页,所以我们调用webdriver的element_to_be_clickable函数,实现自动点击翻页
try:
if(page_number!=2):
submit = WebDriverWait(browser, 10).until(
EC.element_to_be_clickable(
(By.CSS_SELECTOR, '#page > a:nth-child(12)')))
else:
submit = WebDriverWait(browser, 10).until(
EC.element_to_be_clickable(
(By.CSS_SELECTOR, '#page > a.n')))
submit.click()
wait.until(EC.text_to_be_present_in_element(
(By.CSS_SELECTOR, '#page > strong > span.pc'), str(page_number)))
注意这里的翻页函数有两种情况,因为第一页的百度翻页按钮对应的css代码与第一页之后的不一样,算是百度的一个小坑吧,这里就是爬取百度首页的一些注意事项,下面就是对百度知道的爬取
百度知道
选择爬取百度知道是因为百度知道的网页结构相对规整而且百度不限制访问,所以只用采取pyquery就可以收集到标题、作者和URL。比较需要注意的地方是注意对爬取内容的控制,必须要对关键字进行筛选,否则爬取结果很容易就偏离主题。
首先是打开百度知道,在里面输入关键字如"网络安全”,这时你会得到一个页面,前几个是广告,后面就是百度知道的问答了,我们以这个页面为接口开始爬取:
def parse_start_page(html):
doc=pq(html)
items=doc('.list-inner .dt.mb-4.line a').items()
for item in items:
url=item.attr('href')
title=item.text().strip()
author,content=get_page_detail(url)
data={
'title':title,
'href':item.attr('href'),
'author':author,
'content':content
}
在获取了当前界面每个问答的URL之后,我们就可以点进去进行问题的最佳回答进行爬取,这里使用正常的pyquery就可以获取文章的主体内容了
def get_page_detail(url):
author=[]
content=[]
response=requests.get(url).content
doc=pq(response)
#print(doc)
items=doc('.grid.qb-content').items()
for item in items:
# url=item.find('.wgt-related.mt-5.mod-shadow .related-list.line li a').attr('href')
#title=item.find('.wgt-related.mt-5.mod-shadow .related-list.line li a').text()
urls = item.find('.wgt-related.mt-5.mod-shadow .related-list.line li a').items()
for url in urls:
url=url_title+url.attr('href')
get_inside_page(url)
author=item.find('.wgt-best .wgt-replyer-all .wgt-replyer-all-uname').text()
content=item.find('.wgt-best .bd.answer .line.content .best-text.mb-10').text().strip()
return author,content
我这里的函数是用来收集首页的具体信息,每一个百度知道的回答页面的最下面都有其他类似问题的这一个链接框,我们每进入一个知道的界面都会有这一界面,所以我们就迭代这个框里的内容就行了,这个get_page_detail函数可以获取这个框内的所有链接,我们对此进行迭代访问就行了,我们再定义一个函数,加入关键字筛选功能:
def judge_title(page_data, item,title):
global num
global old_url
print(num)
if not db[MONGO_TABLE].find_one({'title': page_data['title']}):
if title.find(u"网") != -1 and title.find(u"络") != -1 and title.find(u"安")!= -1:
print(page_data)
save_to_mongo(page_data)
print('--------------')
urls = item.find('.wgt-related.mt-5.mod-shadow .related-list.line li a').items()
for url in urls:
if title.find(u"网")!= -1 and title.find(u"络")!= -1 and title.find(u"安")!= -1:
url = url_title + url.attr('href')
get_inside_page(url)
else:
print('a')
num=num-1
break
这样理论上我们能爬取到所有的关于网络安全的百度知道的答案,这就是关于pyquery和webdriver的简单使用以及对百度首页和百度知道的简单界面,大多数不限制访问的界面都可以通过这种方法进行爬取了。