欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

通过scrapy实现简单爬虫

程序员文章站 2022-01-20 23:15:13
...

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调试。

相关标签: scrapy