您的位置:首页 > 数据库 > Mongodb

Scrapy+Selenium+PhantomJS+MongoDB实现获取动态数据

2017-04-01 00:00 477 查看
摘要: PhantomJS实现Scrapy抓取动态数据

项目源码下载:码云--推荐,Github

背景介绍

问题:由于有些网站的数据由动态获取(Ajax、JSP)而来,而一般爬虫只能爬取静态数据。爬取到数据后存入MongoDB。

思路:用PhantomJS来模仿用户的动作(如点击、下拉等)来实现完全获取网页的数据以及元素。

缺点:受限于网络状况,PhantomJS拉取数据时很慢;效率不高、占用内存大,个人电脑无法实现大量爬取。

开始实施

用命令行启动一个Scrapy项目

MacBook-Pro:project_scrapy lewisgong$ scrapy startproject demo
New Scrapy project 'demo', using template directory '/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/scrapy/templates/project', created in:
/Users/lewisgong/PycharmProjects/project_scrapy/project_scrapy/demo

You can start your first spider with:
cd demo
scrapy genspider example example.com

用Pycharm打开该项目,项目结构如下:



在middlewares.py中添加一个类,来实现PhantomJS处理爬虫请求。

要点介绍:

首先需要下载PhantomJS驱动,需要在系统环境变量中设置PhantomJS的路径,否则运行时会找不到PhantomJS。或者在初始化时也可以手动指定PhantomJS的路径。

应对懒加载:有些网站需要进行滚动条滚动来加载其余数据,针对此,我们将窗口尽量设置大一点,再用PhantomJS进行滚动。

from selenium import webdriver
from selenium.webdriver.support import ui
from scrapy.http import HtmlResponse
import time

class JavaScriptMiddleware(object):
def process_request(self, request, spider):
if spider.name == "demo":
driver = webdriver.PhantomJS()  # 指定浏览器
print ("PhantomJS is starting...")
driver.set_window_size(1000, 10000) # 尽量将窗口设置大一些,以应对某些网站使用懒加载
driver.get(request.url)
js1 = "var q=document.documentElement.scrollTop=5000"
driver.execute_script(js1)  # 模仿用户操作,下拉滚动条
time.sleep(1)
body = driver.page_source
print ("PhantomJS is visiting "+request.url)
return HtmlResponse(driver.current_url, body=body, encoding='utf-8', request=request)
else:
return

如果需要进行网页点击等操作,可以加上等待事件,等待某个元素加载完毕之后再将PhantomJS得到的数据返回给爬虫处理。举个简单的例子:

wait = ui.WebDriverWait(driver, 15)
driver.find_element_by_xpath('//*[@id="prd_tbox"]/li[3]/a').click()
wait.until(lambda driver: driver.find_element_by_xpath('//*[@id="j-comment-section"]/div/div[1]/div[1]/div[1]/span'))

先设定一个等待事件,等待时间为15ms,然后通过xpath找到这个按钮并进行点击,然后可以等待某个元素加载,加载成功即继续,不成功可以进行其他处理。

至此我们的中间件PhantomJS就算设置完了,还需要在Scrapy的配置中启用就可以了,非常方便。

配置MongoDB的传输通道piplines.py

连接所需要的库为pymongo,MongoDB的官方库。

连接MongoDB所需要的所有配置都存在settings里面,这里将其调用出来直接使用就好了。

通过配置pipelines,可以将爬取到的item全部存入MongoDB中。

from scrapy import log
import pymongo
from scrapy.conf import settings

class DemoPipeline(object):
def __init__(self):
try:
connection = pymongo.MongoClient(host=settings['MONGODB_SERVER'], port=settings['MONGODB_PORT'])
db = connection[settings['MONGODB_DB']]
db.authenticate(name=settings['MONGODB_USER'], password=settings['MONGODB_PWD'])
self.connection = db[settings['MONGODB_COLLECTION']]
print("MonoDB connection established...")
except Exception as e:
print("An exception occurred when try to connect to MongoDB: "+str(e))

def process_item(self, item, spider):
computer = dict(item)
self.connection.insert(computer)
log.msg("Computers added to MongoDB database", _level=log.INFO, spider=spider)

return item


Scrapy的settings.py配置文件

要点介绍:

需要设置HTTP headers中的user-agent,让爬虫看起来更像是一个浏览器的请求。

可以在这里配置MongoDB需要使用的地址、数据库名、用户等,当然也可以用其他方法来减少噪音的hardcode

启用刚刚定义的DemoPipelines

禁用Scrapy内置中间件,启用我们自己定义的中间件。

禁用robot.txt,某些网站会根据robot.txt来指定搜索引擎蜘蛛只抓取指定的内容,或者是禁止搜索引擎蜘蛛抓取网站的部分或全部内容。

BOT_NAME = 'demo'

SPIDER_MODULES = ['demo.spiders']
NEWSPIDER_MODULE = 'demo.spiders'

USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.54 Safari/536.5'

MONGODB_SERVER = 'MongoDB server address'
MONGODB_PORT = 27017
MONGODB_DB = 'DB_name'
MONGODB_USER = 'DB_user'
MONGODB_PWD = 'DB_password'
MONGODB_COLLECTION = 'Collection_name'

ITEM_PIPELINES = {
'gm_computer.pipelines.DemoPipeline': 300,
}

DOWNLOADER_MIDDLEWARES = {
'gm_computer.middlewares.JavaScriptMiddleware': 543,
'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,  # 禁用内置的中间件
}

# Obey robots.txt rules
ROBOTSTXT_OBEY = True


设置items.py

item即你要抓取的一个元素的数据集合,最后会通过pipelines将item写入数据库。

import scrapy
from scrapy import Field, item

class DemoItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
demo = Field() #与爬虫中的item['demo']对应


爬虫处理翻页

现在我们的基本配置以及全部完成了,剩下的就是要写一个爬虫来处理数据了!在spider目录下新建一个爬虫demo.py

# -*- coding: utf-8 -*-
from scrapy.spiders import CrawlSpider
from scrapy.http import Request
from scrapy.selector import Selector
from gm_computer.items import DemoItem # 如果Pycharm出现红线,忽略即可

"""
设置页面编码
"""
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

class ComputerSpider(CrawlSpider):
name = "demo"
start_urls = ["https://my.oschina.net/lewisgong"]
allowed_domains = ["oschina.net"] # 允许访问的域名,如果访问的页面不是在该域名下,则爬虫终止

def parse(self, response):
"""
处理页面数据
"""
item = DemoItem()
selector = Selector(response)
item['demo'] = selector.xpath('xpath of element').extract()[0]
yield item

if True: # 判断是否有下一页,条件自己定义
yield Request(url="下一页的地址", callback=self.parse) # 将下一页的地址传回parse()继续抓取数据

到这里就结束啦,本人也是个小菜鸟,在不断学习中,欢迎指教。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息