​http://computational-communication.com/post/bian-cheng-gong-ju/2014-06-25-searching-weibo-with-selenium​



​1、模拟登录​

最近由于工作需要,编了一个小程序来实现某博搜索数据的抓取。为什么要写这个程序呢,因为某博开放的API接口里,并没有search这个接口,而这个接口在鄙人看来恰恰是最有价值的一个接口,可以返回定制关键词的所有微博(说所有也不准确,因为微博搜索的搜索限制最多返回一千条,所以往回追的话,最多只能抓到当天的1000条数据)。

之前用其他现成的爬虫软件也能抓,但是多少都有点麻烦,禁JS啦,抓下来合并啦等,所以才下定决心自己用python写一个。

在写代码前,设计了这个程序的功能和流程:
1、模拟登录;
2、输入关键词搜索;
3、解析页面;
4、翻页;
5、重复3

这个小程序用到的主要技术是selenium,一个web自动化测试工具,由此可见,我们想要做的,就是把人工一页页去翻,去粘贴复制的工作交给程序去做,原理上并没有啥高大上的。

好,闲话少说,上菜!

先把所有用到的包都放上面,后面都会用得上,除了selenium需要另外安装之外,其他都是python自带的包,安装selenium的方法,大家可以自己去搜索。

from selenium import webdriver
import selenium.webdriver.support.ui as ui
from selenium.webdriver.common.action_chains import ActionChains
from time import sleep
from random import choice
import re

接下来使用selenium打开浏览器,我用的是Chrome,你也可以用Firefox:
browser = webdriver.Chrome() # 打开谷歌浏览器
wait = ui.WebDriverWait(browser,10) # 设定最长等待加载时间为10秒
browser.get("http://s.weibo.com/") #打开微博搜索的地址

打开页面之后,默认是没有登录的,所以我们需要模拟登陆

1、模拟登录

def login(username,password):
wait.until(lambda browser: browser.find_element_by_xpath("//a[@node-type='loginBtn']"))#找到左上角登录按钮
browser.find_element_by_xpath("//a[@node-type='loginBtn']").click() #点击登录按钮
wait.until(lambda browser: browser.find_element_by_xpath("//input[@name='username']")) #等待登录页面出现
user = browser.find_element_by_xpath("//input[@name='username']")
user.clear()
user.send_keys(username) #输入用户名
psw = browser.find_element_by_xpath("//input[@name='password']")
psw.clear()
psw.send_keys(password) #输入密码
browser.find_element_by_xpath("//div[6]/a/span").click() #点击“登录”

如果顺利的话,我们就登录微博了,接下来要输入我们要查询的关键词,进行搜索了。

2、输入关键词搜索

def search(searchWord):
wait.until(lambda browser: browser.find_element_by_class_name("gn_name")) #等待用户名出现,确认登录成功
inputBtn = browser.find_element_by_class_name("searchInp_form") #找到搜索框
inputBtn.clear()
inputBtn.send_keys(searchWord.strip().decode("gbk")) #输入搜索关键词
browser.find_element_by_class_name('searchBtn').click() #点击“搜索”

完成这一步之后,页面就会把第一页搜索结果展示出来。

3、解析页面

def gettext():
content =[] #定义一个list,用来装一条条的微博
wait.until(lambda browser: browser.find_element_by_class_name("search_page_M")) #等待翻页的元素出现
texts = browser.find_elements_by_xpath("//dl[@action-type='feed_list_item']/dd[@class='content']/p[@node-type='feed_list_content']/em") #获取微博内容
#print len(texts)
for n in texts:
try:
emojiToDie = re.compile(u'[\U00010000-\U0010ffff]')
except re.error:
emojiToDie = re.compile(u'[\uD800-\uDBFF][\uDC00-\uDFFF]')
mytext = emojiToDie.sub(u'', n.text) ##emojiToDie 顾名思义,是为了解决微博文本内容里的emoji图像而建立的一个正则表达式,我为什么这么恨emoji呢,因为你在往数据库里存,在解析它的时候,都会报错,所以干脆给它过滤掉
content.append(mytext.encode("utf-8")) ##把每一条微博加到容器里
return content

OK,第一页处理完了,接下来怎么到第二页呢?

4、翻页

def nextPage():
wait.until(lambda browser: browser.find_element_by_class_name("search_page_M")) #等翻页的元素出现
if browser.find_elements_by_xpath("//ul[@class='search_page_M']") != None:
nums = len(browser.find_elements_by_xpath("//ul[@class='search_page_M']/li"))
pg = browser.find_element_by_xpath("//ul[@class='search_page_M']/li[%d]/a" %nums) #.text.encode("gbk") #找到“下一页”
y = pg.location['y']+100 #找到“下一页”在页面的高度
browser.execute_script('window.scrollTo(0, {0})'.format(y)) #滚动到“下一页”所在的行,必须让“下一页”出现在画面里,才能进行点击,这一点是血的教训
ActionChains(browser).move_to_element(pg).click(pg).perform() #鼠标放到下一页上,点击,为啥不直接用click呢,因为会报错,说元素not clickable,泪的教训

5、组合

所有的功能都完成了,接下来要让它能循环地去抓取,我们还需要写个main()函数

def main():
login()
search(Keyword)
text =[]
for i in range(0,10):
text=text +gettext()
sleep(choice([1,2,3,4]))##随机等待1或2或3或4秒,别抓太勤,微博会怀疑你是机器人的
nextPage()

小程序基本可以满足对微博搜索内容的抓取,但仍有需要完善的地方,比如如何实现代理IP,如何识别验证码,期待大神帮忙把它变得更丰满,在此抛砖引玉了~

程序源代码:https://github.com/terry2tan/weibo_search