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

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

项目源码下载:码云--推荐,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的配置中启用就可以了,非常方便。

扫描二维码关注公众号,回复: 3070226 查看本文章

配置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()继续抓取数据

猜你喜欢

转载自blog.csdn.net/m0_37995876/article/details/81096202
今日推荐