【评论文本分类】1.爬取评论数据

环境配置

  • Ubuntu 16.04
  • Python 3.5

技术框架

  • Scrapy
  • Selenium
  • PhantomJS

需求目标

对网址http://liuyan.cjn.cn/index.html进行数据爬取

本文爬虫有三层爬取,爬取结构层次如图所示,

  • 主页面

mark

  • 列表页面,需要利用selenium+phantomJS模拟点击加载更多按钮

mark

  • 详情页面

mark

  • 主页面中的红框中的各区(功能区)政府部门法检及其他单位等作为一级类保存,然后依次爬取一级类中各个分类
  • 进入到列表页面,因为此页面是动态加载,并且是简介列表,因此需要加载完所有列表进入到详情页面。
  • 进入到详情页面,爬取相应内容。

设计方案

动态爬取数据一般有两种方法

  • 分析包,构造Request
  • 通过模拟浏览器行为加载页面

通过尝试,第一种方法对于此网站不适合,采用第二种方法。

采用Scrapy+Selenium+PhantomJS来进行动态网页的爬取。

Selenium

Selenium是一个自动化测试工具,本文用到的是其Webdriver,用其来操作浏览器,可以操作多种主流浏览器,如Chrome,Firefox等,下文中的PhantomJS是一种无界面的浏览器。

PhantomJS

PhantomJS是一个无界面浏览器,提供JavaScript接口。通过这个工具,可以进行页面的加载、解析、操作等。

爬取方案

  • 先爬取主页面各个主类(如各区(功能区)政府部门等)下的子类链接,如(江岸区、江夏区等)
  • 按照先前爬取的子类链接依次打开跳转到列表界面,然后利用Selenium+PhantomJS模拟浏览器动态加载完全部列表,解析出所有列表的链接,跳转到详情页面
  • 进入到详情页面,解析所要提取的内容

详细步骤

安装Scrapy

sudo pip3 install scrapy

安装PhantomJS

  1. 安装PhantomJS

    sudo apt-get install phantomjs
  2. apt-get会安装不完整,需要安装以下

    sudo apt-get install nodejs
    sudo apt-get install nodejs-legacy
    sudo apt-get install npm
    sudo npm -g install phantomjs-prebuilt

安装Selenium

sudo pip3 install selenium

使用Scrapy

  1. 创建新工程

    scrapy startproject xxxx
  2. 编辑items.py文件

    from scrapy import Item
    from scrapy import Field
class MessageboardspiderItem(Item):
# define the fields for your item here like:

dir_name=Field()
url=Field()
title=Field()
domain=Field()
type=Field()
content=Field()


3. 编写Spider

流程:

- 先通过scrapy爬取`主页面`上的所有子分类链接,

- 然后依次利用`PhantomJS`模拟点击`列表页面`的`加载更多`按钮,动态加载所有列表项,然后保存网页源码,抽取出其中的列表项的链接,进入`详情页面`

此两过程的代码都在`parse(self,response)`方法中

- 通过`parse_detailed_remark(self,response)`方法,解析出需要的内容

【注】目前版本爬取`主页面`上不同的主类需要手动改动`baseDir`与`self.start_urls`

```python
import os
import stat
import scrapy
import time
from selenium import webdriver
from scrapy.selector import Selector
from scrapy.http import HtmlResponse
from messageBoardSpider.items import MessageboardspiderItem


baseDir = '/home/t/dataset/msgBoard/department/' #爬取不同主分类,需要手动改动
baseUrl='http://liuyan.cjn.cn'
global subclass_name
global brower
class DistrictSpider(scrapy.Spider):
name='spider'
def __init__(self):
global brower
self.start_urls=['http://liuyan.cjn.cn/forum/list?fid=4'] #爬取不同主分类,需要手动改动
brower=webdriver.PhantomJS() #创建PhantomJS浏览器

def parse(self,response):
global brower
global subclass_name

subclasses=response.xpath('/html/body/div[7]/ul/li/b/a') #解析出所有子分类
for subclass in subclasses: #逐条解析子分类

subclass_name=subclass.xpath('text()').extract() #解析

#make district directory
self.mkdirs(baseDir+subclass_name[0])

#extrat new link
link=subclass.xpath('@href').extract() #解析出子类的链接
#joint link
link=str(baseUrl+link[0].split('..')[1]) #拼接链接

brower.get(link) #利用PhantomJS打开链接
#进行动态解析,直到没有'加载更多'按钮之后停止
while True:
try:
more=brower.find_element_by_id('show_more') #找到'加载更多'按钮
time.sleep(0.5)
more.click()
time.sleep(0.5)
except:
with open(baseDir+subclass_name[0]+'/web_page.txt','w',encoding='utf-8') as f:
f.write(brower.page_source)
print('ending')
break


#对加载完后的源码进行解析,解析出列表标题
items=brower.find_elements_by_xpath('//*[@id="list_content"]/li/h2/b/a')
for item in items:
#解析出列表标题链接
title_link=item.get_attribute('href')
print(title_link+'.........')
yield scrapy.Request(url=title_link,callback=self.parse_detailed_remark)

#解析详情页面
def parse_detailed_remark(self,response):

global subclass_name
item=MessageboardspiderItem()
item['dir_name']=subclass_name[0]
item['url']=response.url
item['title']=response.xpath('/html/body/div[6]/h2/b/text()').extract()
item['domain']=response.xpath('/html/body/div[6]/h3/em[1]/a/text()').extract()
item['type']=response.xpath('/html/body/div[6]/h3/em[2]/a/text()').extract()
item['content']=response.xpath('//*[@id="zoom"]/text()').extract()
yield item


def mkdirs(self,path):

if not os.path.exists(path):
os.makedirs(path)
os.chmod(path,stat.S_IRWXU|stat.S_IRWXG|stat.S_IRWXO)
  1. 编辑pipelines.py文件

    import json
    import codecs
    baseDir = '/home/t/dataset/msgBoard/department/'

    class DistrictPipeline(object):
    def process_item(self, item, spider):
    with codecs.open(baseDir+item['dir_name']+'/data.json','a+',encoding='utf-8') as f:
    self.file=f
    line=json.dumps(dict(item),ensure_ascii=False)+'\n'
    self.file.write(line)

    return item
  2. 编辑settings.py文件

    编辑pipelines的设置,把如下内容的注释去掉即可

    #ITEM_PIPELINES = {
    # 'messageBoardSpider.pipelines.DistrictPipeline': 300,
    #}
  3. 运行爬虫

    在项目根目录下新建一个main.py文件,运行爬虫执行该文件即可。

    mark

    from scrapy.cmdline import execute
    execute(['scrapy','crawl','spider'])

    【注】execute(['scrapy','crawl','spider'])

    其中spider是爬虫名,按需更改即可。