您的位置:首页 > 移动开发 > 微信开发

数据采集(六):scrapy爬取搜狗微信新闻+selenium模拟鼠标点击

2017-08-01 10:41 369 查看

scrapy框架解析

scrapy是一个流行的爬虫框架,为什么要用它呢?前面我们已经通过xpath或beautifulsoup实现了爬虫,scrapy又有什么不同?我在初步理解了这个框架之后,感觉它很灵活,很强大。

使用beautifulsoup库我们可以很方便的实现单个爬虫,最后的结果写进了一个字典。但是当考虑一个项目中有多个爬虫,或者需要将最后的结果保存进json、csv文件,mysql数据库、mogodb数据库,或者网页是包含js的动态网页时,请使用scrapy。

下面这张图可以帮助我们宏观地把握这个框架:



绿色的箭头代表了工作过程的流向。scrapy内部有一个调度器,它根据提供的初始链接,去下载网页内容。有一些动态的网页不能直接通过request下载,比如需要点击鼠标,下拉滑块等操作,html才能加载完整,这个时候需要用到DownloaderMiddlewares,即下载器中间件。

当网页下载之后,然后会通过response交给爬虫来处理了。爬虫会返回两类内容,一类是爬取的结果,它封装在items里,items可以类比一个字典,是一个scrapy自定义的数据结构,把它交给Item Pipeline处理;一类是url链接,这是个更深层次的网页,遵循同样的流程,把它抛给调度器,重复这个过程。后面解析代码时会详细看到这个过程的实现。

SpiderMiddlewares我暂时还没怎么接触到。

Item Pipeline负责将item保存在文本文件或者数据库。

可以看到框架中每个部分分工明确,可以很方便的定制。

爬取搜狗微信新闻

下面以爬取搜狗微信新闻为例,对scrapy一探究竟。网址为搜狗微信频道。我们的目的是爬取首页所有新闻的标题、发布时间以及发布者。可以看到首页新闻仅有20条,点击“加载更多内容”之后,其余的新闻才能显现出来。

在scrapy中怎么着手呢?建立一个空的scrapy项目之后,我们会发现里面有items.py、middlewares.py、pipelines.py、settings.py、还有一个spiders文件夹。这是都
4000
是我们施展拳脚的地方,当然一些爬虫项目不会用到全部,那剩余的各种,我们都不用管,交给框架处理就好。

确定爬取字段

首先明确爬取的字段—title、time、post_user。这个在items.py中指定。

# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html 
import scrapy

class WxnewsItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()

title=scrapy.Field()
time=scrapy.Field()
post_user=scrapy.Field()


编写爬虫

然后在spiders文件夹中建立一个py文件,比如wxnews_spider.py,文件名字是无所谓的。在py文件中,要写一个符合规范的类,比如:

# -*- coding:utf-8 -*-
import scrapy
from wxnews.items import WxnewsItem

class WxnewsSpider(scrapy.Spider):
name = 'wxnews'
start_urls = [
'http://weixin.sogou.com'
]

def parse(self, response):
news_href_list=response.xpath('//ul[@class="news-list"]/li/div[2]/h3/a/@href')
#print response.url
for href in news_href_list:
url=response.urljoin(href.extract())
yield scrapy.Request(url,callback=self.parse_news)

def parse_news(self, response):
title=response.xpath('.//div[@id="page-content"]/div/h2/text()').extract_first()
time=response.xpath('.//div[@id="page-content"]/div/div[1]/em[1]/text()').extract_first()
post_user=response.xpath('.//a[@id="post-user"]/text()').extract_first()

#print title.strip()
#print time.strip()
#print post_user.strip()

#print " "

#yield {'title':title,
#      'time':time,
#     'post_user':post_user
# }

news=WxnewsItem()
news['title']=title.strip()
news['time']=time
news['post_user']=post_user

yield news


解释一下上述代码,首先需要导入item类,然后写一个爬虫类体。它是一个派生类,name是爬虫名字、start_url是爬虫开始的url,都是从父类继承的属性。parse也是继承函数,程序会默认调用。在程序中我们也写了一个自定义的解析函数parse_news。它和parse相同,都接受response对象。都可通过yield抛出两类对象,一类是item,一类就是request。request通过callback指定了对获取后的网页内容采用何种解析方法,比如下句:

yield scrapy.Request(url,callback=self.parse_news)


yield类比return,不同之处在于执行yield之后会继续执行函数体中后续代码。

可以看到在parse函数中,一样是通过xpath定位并解析出想要的元素。

将结果写入文件

到这一步,我们就该考虑怎么把结果保存进文本文件。如果是保存到csv文件或json文件中,那么很方便的是,我们在pipelines中可以什么也不用写,即可完成这一功能。只需要在命令行中执行爬虫时,指定一个文件。如下所示

scrapy crawl wxnews -o result.csv


wxnews是爬虫名字,result.csv是结果文件。

获取需要将结果写入数据库,那么需要在pipelines中写一个自定义的process_item函数,包括怎么连接数据库,和对数据库增删改查的操作。

编写下载中间件,模拟鼠标点击

在本例中,也并非最简单的例子,因为,我们需要模拟鼠标点击的动作,使网页加载出完整内容。我们需要在middlewares.py的process_request函数写这一功能。它涉及到下载这一步骤,接受request,返回response,所以叫下载中间件。详细代码如下:

#-*- coding:utf-8 -*-
from selenium import webdriver
from scrapy.http import HtmlResponse
import time
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from random import choice

class SeleniumMiddleware(object):
def process_request(self, request, spider):
click_page_url="http://weixin.sogou.com"
if request.url==click_page_url:
driver = webdriver.PhantomJS()
try:
driver.get(request.url)
driver.implicitly_wait(3)
time.sleep(5)

look_more=".//div[@class='jzgd']/a"
for n in range(4):
driver.find_element_by_xpath(look_more).click()  # 数据由js来控制,点击后加载数据
time.sleep(5)

true_page = driver.page_source
driver.close()

return HtmlResponse(request.url,body = true_page,encoding = 'utf-8',request = request,)

except:
print "get news data failed"
else:
return None


上述代码引入一个模块叫selenium,它用来模拟浏览器以及鼠标的各种行为。这里的鼠标行为即点击某个元素,比如这里是“look_more”。PhantomJS叫无头浏览器,它是selenium里的,当然selenium里可以模拟很多浏览器,比如chrome,火狐等。无头浏览器不同点是它不需要渲染出花花绿绿的页面,名字起的很到位。从代码中可以看到,模拟了浏览器请求页面以及超时等待等操作。

爬取结果

所讲的例子包含的工作量就是这些。运行之后,看看我们成果:



总共获取约100条数据,因为每页20条新闻,鼠标点击4次,首页新闻可全部加载完。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐