最近一段时间,今日头条各种推送python相关的文档,什么“python都要加入高考了,再不学就out了”等等特别火热,正好公司领导安排我去爬取一些网站新闻信息,可以趁着这个机会学习学习python,所以就决定用python来完成本次的爬取工作。因为之前没有接触过python,所以直接上手遇到了各种各样的问题,还好最后都解决了。
Scrapy简介
Scrapy是Python开发的一个快速,高层次的屏幕抓取和Web抓取框架,用于抓取Web站点并从页面中提取结构化的数据。
下图展示了Scrapy的大致架构,其中包含了主要组件和系统的数据处理流程(绿色箭头表示)。下面会对组件和流程进行了一个简单的解释。
组件
1.Scrapy Engine(Scrapy引擎)
Scrapy引擎是用来控制整个系统的数据处理流程,并进行事务处理的触发。更多的详细内容可以看下面的数据处理流程。
2.Scheduler(调度程序)
调度程序从Scrapy引擎接受请求并排序列入队列,并在Scrapy引擎发出请求后返还给它们。
3.Downloader(下载器)
下载器的主要职责是抓取网页并将网页内容返还给蜘蛛(Spiders)。
4.Spiders(蜘蛛)
蜘蛛是有Scrapy用户自己定义用来解析网页并抓取制定URL返回的内容的类,每个蜘蛛都能处理一个域名或一组域名。换句话说就是用来定义特定网站的抓取和解析规则。
5.Item Pipeline(项目管道)
项目管道的主要责任是负责处理有蜘蛛从网页中抽取的项目,它的主要任务是清晰、验证和存储数据。当页面被蜘蛛解析后,将被发送到项目管道,并经过几个特定的次序处理数据。每个项目管道的组件都是有一个简单的方法组成的Python类。它们获取了项目并执行它们的方法,同时还需要确定的是是否需要在项目管道中继续执行下一步或是直接丢弃掉不处理。
项目管道通常执行的过程有:
清洗HTML数据 验证解析到的数据(检查项目是否包含必要的字段) 检查是否是重复数据(如果重复就删除) 将解析到的数据存储到数据库中
6.Middlewares(中间件)
中间件是介于Scrapy引擎和其他组件之间的一个钩子框架,主要是为了提供一个自定义的代码来拓展Scrapy的功能。
数据处理流程
Scrapy的整个数据处理流程有Scrapy引擎进行控制,其主要的运行方式为:
1.引擎打开一个域名,蜘蛛处理这个域名,并让蜘蛛获取第一个爬取的URL。
2.引擎从蜘蛛那获取第一个需要爬取的URL,然后作为请求在调度中进行调度。
3.引擎从调度那获取接下来进行爬取的页面。
4.调度将下一个爬取的URL返回给引擎,引擎将它们通过下载中间件发送到下载器。
5.当网页被下载器下载完成以后,响应内容通过下载中间件被发送到引擎。
6.引擎收到下载器的响应并将它通过蜘蛛中间件发送到蜘蛛进行处理。
7.蜘蛛处理响应并返回爬取到的项目,然后给引擎发送新的请求。
8.引擎将抓取到的项目项目管道,并向调度发送请求。
9.系统重复第二部后面的操作,直到调度中没有请求,然后断开引擎与域之间的联系。
以上来自网络,现在开始真正的开发:
新建工程:
进入想保存项目的路径执行:
scrapy startproject
目录结构及其说明请自行google或baidu.
在PyCharm中导入:
Spider是整个项目中最核心的类,在这个类里我们会定义抓取对象(域名、URL)以及抓取规则。
在spiders下新建python文件:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import scrapy
from scrapy import Selector
from news_xagx.items import NewsXagxItem
class XiaoHuarSpider(scrapy.spiders.Spider):
name = "xasoftpark"
allowed_domains = ["**********.com"]
start_urls = [
"http://www.**********.com/info/iList.jsp?cat_id=10055",
"http://www.**********.com/info/iList.jsp?cat_id=10056",
"http://www.**********.com/info/iList.jsp?cat_id=10057",
"http://www.**********.com/info/iList.jsp?cat_id=10058",
]
def parse(self, response):
baseUrl = 'http://www.**********.com/'
selector = Selector(response)
links = selector.xpath('/html/body/div[8]/div[1]/ul//li/a/@href')
for link in links:
url = baseUrl + link.extract()
yield scrapy.Request(url, callback=self.parse_news_contents)
#爬取下级页面内容
def parse_news_contents(self, response):
item = NewsXagxItem()
news_date_content = response.xpath('/html/body/div[5]/div/div[5]').xpath('string(.)').extract()[0]
item['newsDate'] = self.get_news_date(news_date_content)
item['title'] = response.xpath('/html/body/div[5]/div/div[3]').xpath('string(.)').extract()[0]
item['content'] = response.xpath('/html/body/div[5]/div/div[@class="cent_nr_box"]').xpath('string(.)').extract()[0]
yield item
#截取日期
def get_news_date(self, content):
data = u'发布时间:'
date_index = content.find(u"发布时间:") + len(u"发布时间:")
news_data = content[date_index : date_index + 10]
return news_data
MongoDB配置,在settings.py中添加MongoDB配置:
ITEM_PIPELINES = {
'news_xagx.pipelines.NewsXagxPipeline': 300,
}
MONGODB_SERVER = "localhost"
MONGODB_PORT = 27017
MONGODB_DB = "news_xa"
MONGODB_COLLECTION = "news"
pipelines.py
# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
import codecs
import json
import pymongo
from scrapy import log
from scrapy.conf import settings
class NewsXagxPipeline:
def __init__(self):
connection = pymongo.MongoClient(settings['MONGODB_SERVER'], settings['MONGODB_PORT'])
db = connection[settings['MONGODB_DB']]
self.collection = db[settings['MONGODB_COLLECTION']]
words_to_filter = ['资金', '政策', 'IT', '创新', '扶持', '项目申报']
def process_item(self, item, spider):
for word in self.words_to_filter:
if word.decode('utf8') in item['title'][0] or word.decode('utf8') in item['content']:
self.collection.insert(dict(item))
log.msg("news added to MongoDB database!",
level=log.DEBUG, spider=spider)
else:
pass
至此,我们来验证下是否成功存入MongoDB中:
mongo命令行输入:
db.news.findOne()
输出:
至此完成scarpy的入库,记录有些简陋,慢慢细化。