通过scrapy实现简单爬虫
Scrapy概述
网络爬虫,大概很多人都听说过吧。
它是通过一定的规则,自动抓取互联网网站上的文章、信息、图片等等内容。
常见的应用就是搜索引擎。
而Scrapy则是实现网络爬虫的方式之一。
官方描述的Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。
可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。
Scrapy安装配置
Scrapy是需要配置Python环境的。所以我们先通过pycharm新建一个project。
配置git
然后安装环境:
pip install scrapy
pycharm并不支持直接创建scrapy的project,所以我们需要手动创建:
scrapy startproject SpiderProject
创建模板
scrapy提供了命令让我们可以根据模板创建spider,这个命令就是genspider
genspider可以直接创建spider的模板,比如我们爬www.ttsla.com:
scrapy genspider ttsla www.ttsla.com
可以通过scrapy genspider -h 查看相关帮助
我们也可以通过scrapy genspider -l 查看可用模板
如果是windows下还需要装个win32模块:
pip install -i https://pypi.douban.com/simple pypiwin32
调试运行
在命令行中调试选择器:
scrapy shell www.ttsla.com
这样我们就可以很方便的在命令行中通过response.css调试选择器,并把正确的调试结果copy到代码中。
实现简单的爬虫功能需要改三个文件:
settings.py
items.py
ttlsa.py
settings.py下需要设置ROBOTSTXT_OBEY,否则会过滤掉不符合ROBOTS协议的url:
ROBOTSTXT_OBEY = False
settings.py中还需要配置ITEM_PIPELINES,这一段代码默认是禁用的:
ITEM_PIPELINES = {
'ttlsaSpider.pipelines.TtlsaspiderPipeline': 300,
}
item.py中定义爬虫爬取结果的结构,可以定义多个,比如标题定义类似于这种:
class TtlsaspiderItem(scrapy.Item):
title = scrapy.Field()
ttlsa.py这个是我自定义的蜘蛛的名字,名字也可以是其他的,我这里只是示例。
如果我们之前执行了创建模板的命令,系统会自动生成这个文件。
其中的parse函数需要自己来写。要注意相互调用的关系。比如最简单的:
def parse(self, response):
item = TtlsaspiderItem()
nodes = response.css(".entry-header .entry-title a")
item['标题'] = nodes.css("::text").extract()
yield item
注意在定义start_urls的时候,要配置好完整的url路径:
start_urls = ['http://www.ttlsa.com']
配好这三个文件,我们就可以scrapy crawl ttlsa -o result.csv来跑一下,
会自动生成一个csv文件
打开csv文件来验证结果。
取数据
通过网站的页面取数据有两种方法:xpath和css。
这两种取数据的方式各有优缺点,可以根据实际情况来分别应用。
通过xpath取出数据,示例如下:
title = response.xpath('//*[@class="grid-8"]/div[1]/div[1]/h1/text()').extract()
通过css取数据,示例如下:
title = response.css(".entry-header .entry-title a::text").extract()
response.xpath会返回一个SelectorList对象,extract后会把selector对象转换成list类型
如果取出来是一个list,可以通过selector[0]取出值.
xpath的值可以通过chrome浏览器的F12的调试功能找,然后把xpath复制出来。
下面是复杂一些的,取日期,其实方法是一样的:
date = response.xpath("//*[@class='entry-meta-hide-on-mobile']/text()").extract()[0].strip().replace("·", "").strip()
strip()方法是去空格和换行符;replace()方法是替换。
contains,我们加上contains,就是class中包含了‘vote-post-up’这个字符串就匹配了,代码如下:
response.xpath("//*[contains(@class, 'vote-post-up')]")
通常这种用法适合class包含了多个字符串的时候进行匹配。
有些时候需要通过正则来匹配,以下代码我们用xpath通过正则过滤掉了中文,只保留数字:
comments_nums = response.xpath("//a[contains(@href, '#article-comment')]/span/text()").extract()[0].strip()
match_re = re.match(".*?(\d+).*", comments_nums)
if match_re:
comments_nums = match_re.group(1)
为了方便调试,我们可以自定义一个main.py,效果和命令行里输入命令是一样的:
from scrapy.cmdline import execute
execute(['scrapy', 'crawl', 'ttlsa'])
export
数据生成以后我们可以导出。我们需要修改pipelines.py的文件,可以通过pipeline将数据保存到json或数据库等。
Json的导出可以自定义方法,也可以使用自带的JsonItemExporter方法:
#使用scrapy内置JsonItemExporter的方法输出json
class JsonItemExporterPipeline(object):
def __init__(self):
self.file = open("result.json", "wb")
self.export = JsonItemExporter(self.file, ensure_ascii=False, encoding='utf8')
self.export.start_exporting()
def close_spider(self):
self.export.finish_exporting()
def process_item(self, item, spider):
self.export.export_item(item)
return item
导出到数据库的方法也是类似的,我们以MySQL为例。我们首先需要装个mysqlclient
提供一个链接:
https://www.lfd.uci.edu/~gohlke/pythonlibs/#
这里有非常多适配windows的python库,搜一下mysql就能找出来,然后直接pip install
注意cp35代表python3.5的版本,win32代表32位的系统。
然后装mysql建库建表就不说了,我是直接用docker建库。建好表以后,可以增加设置一个id字段作为自增字段。
编写pipelines.py,添加自定义类,我这里就只两个字段:
class MysqlPipelines(object):
def __init__(self):
self.conn = MySQLdb.connect(host="192.168.99.100", user="root", passwd="root", port=3316, db="article_spider", charset="utf8", use_unicode=True)
self.cursor = self.conn.cursor()
def process_item(self, item, spider):
insert_sql = """insert into ttlsa (title, url) values (%s, %s)"""
self.cursor.execute(insert_sql, (item["title"], item["url"]))
self.conn.commit()
注意修改settings.py里的配置文件
运行main.py调试。