参考:https://scrapy-chs.readthedocs.io/zh_CN/latest/intro/tutorial.html#intro-tutorial
利用scrapy来创建任务,爬取王者荣耀的英雄头像。
下载scrapy
pip install scrapy
创建一个项目
scrapy startproject king_head
目录结构
$ tree
.
├── king_head
│ ├── __init__.py
│ ├── __pycache__
│ ├── items.py # 项目中item文件,保存爬取数据的容器
│ ├── middlewares.py
│ ├── pipelines.py # 用来对items里面提取的数据做进一步处理,如保存等
│ ├── settings.py # 项目设置文件
│ └── spiders # 爬取脚本所在目录
│ ├── __init__.py
│ └── __pycache__
└── scrapy.cfg # 项目配置文件
4 directories, 7 files
在spiders目录下创建我们的第一个爬虫。
我们创建一个爬虫,必须继承scrapy.Spider类,并且需要定义以下三个属性:
假设爬取王者荣耀的英雄头像
import scrapy
class HeroItem(scrapy.Item):
# 抓取的内容
name = scrapy.Field()
url = scrapy.Field()
上面类中的name,url就像是字典中的“键”,爬到的数据就像似字典中的“值”。
from scrapy.spiders import CrawlSpider
from king_head.items import HeroItem
class Spider(CrawlSpider):
name = 'hero_head' # 爬虫的名字,必须唯一
allowed_domains = ['pvp.qq.com'] # 爬取的域名
start_urls = ['https://pvp.qq.com/web201605/herolist.shtml'] # 爬取URL
def parse(self, response): # 回调函数,处理response并返回处理后的数据和需要跟进的url
for line in response.xpath('//ul[@class="herolist clearfix"]/li'):
# 初始化item存储爬取的信息
item = HeroItem()
item["name"] = line.xpath('a[@target="_blank"]/img/@alt').extract()
item["url"] = line.xpath('a[@target="_blank"]/img/@src').extract()
yield item # 生成式
scrapy crawl hero_head -o item.json # -o 指定保存到文件
程序运行到这里可以获取到头像和url,并且存储到本地的json文件中。
# 修改settings.py文件,添加编码格式,支持utf8
FEED_EXPORT_ENCODING = 'UTF-8'
下面我们将获取到的内容写入到数据库,包括英雄的名字和头像的链接地址
首先需要在settings.py配置文件中开启通道
ITEM_PIPELINES = {
'king_head.pipelines.KingHeadPipeline': 300,
}
MYSQL_HOST = '127.0.0.1'
MYSQL_PORT = 3306
MYSQL_USER = 'root'
MYSQL_PWD = '123456'
MYSQL_DB = 'test'
编写pipelines.py,将结果写入数据库
import pymysql
class KingHeadPipeline(object):
def __init__(self):
'''
初始化方法
'''
# 创建数据库链接
self.client = pymysql.Connect(
'127.0.0.1', 'root', '12345678','test', 3306, charset='utf8'
)
# 创建游标
self.cursor = self.client.cursor()
def open_spider(self, spider):
'''
爬虫启动的时候会调用一次
:param spider:
:return:
'''
print('爬虫开启')
pass
def process_item(self, item, spider):
'''
这个方法必须实现,爬虫文件中所有的item 都会经过这个方法
:param item: 爬虫文件传递过来的item对象
:param spider: 爬虫文件实例化的对象
:return:
'''
# 存储到本地json文件
data_dict = dict(item)
# 插入数据库
sql = "insert into hero_info(%s,%s) values('%s','%s')" % ("hero_name", "hero_url", data_dict["name"][0], "https:" + data_dict["url"][0])
try:
self.cursor.execute(sql)
self.client.commit()
except Exception as err:
self.client.rollback()
print(err)
# 如果有多个管道文件,一定要return item , 否则下一管道无法接收到item
print('经过了管道')
return item
def close_spider(self, spider):
'''
爬虫结束的时候调用一次
:param spider:
:return:
'''
# self.file.close()
self.client.close()
self.cursor.close()
print('爬虫结束')
编写pipelines.py,根据请求到的URL去下载图片
import pymysql
from urllib import request
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
class KingHeadPipeline(object):
def __init__(self):
'''
初始化方法
'''
# 创建数据库链接
self.client = pymysql.Connect(
'127.0.0.1', 'root', '12345678','test', 3306, charset='utf8'
)
# 创建游标
self.cursor = self.client.cursor()
def open_spider(self, spider):
'''
爬虫启动的时候会调用一次
:param spider:
:return:
'''
print('爬虫开启')
pass
def process_item(self, item, spider):
'''
这个方法必须实现,爬虫文件中所有的item 都会经过这个方法
:param item: 爬虫文件传递过来的item对象
:param spider: 爬虫文件实例化的对象
:return:
'''
# 存储到本地json文件
data_dict = dict(item)
request.urlretrieve("https:" + data_dict["url"][0], r"images/%s.jpg" % (data_dict["name"][0]))
# 如果有多个管道文件,一定要return item , 否则下一管道无法接收到item
print('经过了管道')
return item
def close_spider(self, spider):
'''
爬虫结束的时候调用一次
:param spider:
:return:
'''
# self.file.close()
self.client.close()
self.cursor.close()
print('爬虫结束')