摘要:
如果我们把互联网比作一张大的蜘蛛网,数据便是存放于蜘蛛网的各个节点;而爬虫就是一只小蜘蛛,沿着网络抓取自己的猎物(数据)爬虫指的是:向网站发起请求,获取资源后分析并提取有用数据的程序;从技术层面来说就是 通过程序模拟浏览器请求站点的行为,把站点返回的HTML代码/JSON数据/二进制数据(图片、视频) 爬到本地,进而提取自己需要的数据,存放起来使用;
友情提示:
本文所有关于 python 的基本代码都是基于 python3.7 的,不同 python 版本之间会有些许差异,但不影响我们对 整体的把握和了解。
由于 本文的源代码实现依赖于python源代码,所以阅读本文需要读者了解关python的基本语法,关于python基本语法 请移步菜鸟教程 http://www.runoob.com/python/python-tutorial.html,以及还有mysql的基本操作,需要读者有基本的了解
一. Scrapy概述
-
Scrapy是用纯Python实现一个为了爬取网站数据、提取结构性数据而编写的应用框架,用途非常广泛。
-
框架的力量,用户只需要定制开发几个模块就可以轻松的实现一个爬虫,用来抓取网页内容以及各种图片,非常之方便。
我们在项目中主要用到了如下加黑的部分
-
Scrapy Engine(引擎): 负责Spider、ItemPipeline、Downloader、Scheduler中间的通讯,信号、数据传递等。
-
Scheduler(调度器): 它负责接受引擎发送过来的Request请求,并按照一定的方式进行整理排列,入队,当引擎需要时,交还给引擎。
-
Downloader(下载器):负责下载Scrapy Engine(引擎)发送的所有Requests请求,并将其获取到的Responses交还给Scrapy Engine(引擎),由引擎交给Spider来处理,
-
Spider(爬虫):它负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器)
-
Item Pipeline(管道):它负责处理Spider中获取到的Item,并进行进行后期处理(详细分析、过滤、存储等)的地方.
-
Downloader Middlewares(下载中间件):你可以当作是一个可以自定义扩展下载功能的组件。
-
Spider Middlewares(Spider中间件):你可以理解为是一个可以自定扩展和操作引擎和Spider中间通信的功能组件(比如进入Spider的Responses;和从Spider出去的Requests)
引用链接:https://www.jianshu.com/p/306e03c618cf
二. 安装python
下载地址:https://www.python.org/downloads/windows/
本文项目环境:window10
python版本: Windows x86-64 executable installer
三、安装pycharm
下载地址:https://www.jetbrains.com/pycharm/download/#section=windows,并选择window版本安装
四、安装 scrapy 框架
有一点 不要在pycharm上直接安装 scrapy 不知道因为什么一直失败,莫名的尴尬
我们直接在 C:\Users\jie\AppData\Local\Programs\Python\Python37\Scripts 这个scripts目录下打开cmd安装
- 首先看这个方法能不能成功:pip install scrapy
- 如果使用上面的命令太慢。国内可以使用豆瓣源进行加速:pip install -i https://pypi.douban.com/simple scrapy
1、如果失败考虑安装whl格式的包:
如果安装whl格式包则需要安装wheel库,安装方法:pip install wheel
2、由于scrapy依赖twiste,先要安装twiste:
下载地址:https://www.lfd.uci.edu/~gohlke/pythonlibs/
在网页中搜索twisted找到对应的whl包并下载:Twisted‑18.4.0‑cp37‑cp37m‑win_amd64.whl
根据Python版本选择合适的包,名称中间的cp37是python3.7的意思,amd64是python的位数)
下载完成后使用cmd命令打开windows的命令行窗口,进入whl包所在的文件夹执行如下命令:pip install [whl]
[whl]是whl包的名字,即:pip install Twisted‑18.4.0‑cp36‑cp36m‑win_amd64.whl
3、scrapy依赖lxml包,安装lxml: pip install lxml
4、下载地址:https://www.lfd.uci.edu/~gohlke/pythonlibs/ 在网页中搜索scrapy下载scrapy的whl包
Scrapy‑1.5.0‑py2.py3‑none‑any.whl
下载完成后使用cmd命令打开windows的命令行窗口,进入whl包所在的文件夹执行如下命令:pip install [whl]
[whl]是whl包的名字,即:pip install Scrapy‑1.5.0‑py2.py3‑none‑any.whl
这样安装一定成功
然后使用 pycharm 记得先在 file -》setting 中更改为你的 python 环境
这样环境就算是安装完成了
五、创建项目(如下代码为demo)
5.1创建一个新项目 demo1
5.2 代建 scrapy 框架
创建 Tengxun 在 编辑器底部栏的 terminal 终端 中输入
scrapy startproject Tengxun
5.3 分析我们要做什么操作,以如下几点
- 新建项目 (scrapy startproject xxx):新建一个新的爬虫项目
- 明确目标 (编写items.py):明确你想要抓取的目标
- 制作爬虫 (spiders/xxspider.py):制作爬虫开始爬取网页
- 存储内容 (pipelines.py):设计管道存储爬取内容
5.4 修改setting的代码 ,在setting 文件夹下加入如下 code
# 函数的执行顺序,序号越小,优先级越高
ITEM_PIPELINES = {
'HupuSpider.pipelines.HupuspiderPipeline': 1,
'HupuSpider.pipelines.HupuImagesPipeline': 2,
}
LOG_LEVEL='DEBUG'
ROBOTSTXT_OBEY = True
5.5 创建 item
import scrapy
class HupuspiderItem(scrapy.Item): (注意这里的类名你需要根据自己的命名做更改)
# 明星名称
starname = scrapy.Field()
# 明星url
starurl = scrapy.Field()
# 简介内容
content=scrapy.Field()
# 简介标题
contenttitle=scrapy.Field()
# 拍的电影图片
imageurl=scrapy.Field()
5.6 爬取我们想要获得数据的网页,进而分析
创建如下文件
import scrapy
class demoSpider(scrapy.Spider):
name = "dmoz"
allowed_domains = ["dmoz.org"]
start_urls = [
"http://www.dmoz.org/Computers/Programming/Languages/Python/Books/",
"http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/"
]
def parse(self, response):
filename = response.url.split("/")[-2] + '.html'
with open(filename, 'wb') as f:
f.write(response.body)
获取到html 然后 我们在对其进行分析
5.7 编写我们的逻辑代码 (刚刚创建的文件中)
# -*- coding: utf-8 -*-
from HupuSpider.items import HupuspiderItem
import scrapy
import os
class NbaNewsSpider(scrapy.Spider):
name = 'tengxun'
# allowed_domains = ['v.qq.com/x/hotlist/search/?channel=556']
start_urls = ['https://v.qq.com/x/hotlist/search/?channel=556']
def parse(self, response):
# 抓取响应体
# filename = response.url.split("/")[-5] + '.html'
# print(response.extract())
# with open(filename, 'wb') as f:
# f.write(response.body)
# 明星排行榜单
result = response.xpath('/html/body/div[3]/div[1]/div[1]/div[2]/ul/li/div[1]/a')
# print(result.extract())
# 榜单明星名字
startman = result.xpath('.//text()').extract()
# print(startman)
# 榜单明星具体信息地址
startmanurl = result.xpath('.//@href').extract()
# print(startmanurl)
# 存放 bean 数据
items = []
# 创建明星目录
for i in range(0,len(startman)):
item = HupuspiderItem()
# 指定存储目录+明星名字
teamFilename="./今日明星/"+startman[i]
# 如果目录不存在,则创建目录
if (not os.path.exists(teamFilename)):
os.makedirs(teamFilename)
item['starname']=startman[i]
item['starurl']=startmanurl[i]
items.append(item)
# print(items)
# #发送每个明星的url的Request请求,得到Response连同包含meta数据
# # 一同交给回调函数 second_parse 方法处理
for item in items:
for i in range(1,2):
# tempurl = item['starurl'].replace('.html','')
# teamurl = tempurl + '-' + str(i) + '.html'
yield scrapy.Request(url=item['starurl'], meta={'meta_1': item}, callback=self.second_parse)
# 对每支球队的url进行爬取
def second_parse(self,response):
# items = 0
# 提取每次Response的meta数据(就是上个函数保存下来的)
item = response.meta['meta_1']
# 获得明星个人简介
temp = response.css('.desc_text').xpath('string(.)').extract()[0]
item['content'] = temp
# print(temp)
# 明星个人电影图片
temp = "";
imaurl = response.xpath('/html/body/div[2]/div[2]/div[1]/div[2]/div[2]/div[2]/div[1]/div[1]/ul/li/a/img/@src').extract()
for i in range(0, len(imaurl)):
temp = temp+","+imaurl[i]
item['imageurl'] = temp
item['contenttitle'] = item['starname']
yield item
5.8 在 pipelines 文件中编写item 的处理(含有创建 txt 文件,图片下载处理,上传信息到数据库)
# -*- coding: utf-8 -*-
from scrapy.pipelines.images import ImagesPipeline
from scrapy.utils.project import get_project_settings
import scrapy
import shutil
import pymysql
import os
class HupuspiderPipeline(object):
def process_item(self, item, spider):
# 明星名字作为简介txt的名字
filename = item['contenttitle']
filename += ".txt"
# 个人简介放到个人相对应的文件夹中
savepath='./今日明星'+'/'+item['starname']+'/'+filename
fp = open(savepath, 'w', encoding='utf-8')
fp.write(item['content'])
fp.close()
host = '127.0.0.1'
user = 'root'
psd = 'root'
db = "python"
c = "utf8"
port = 3306
# 数据库连接
con = pymysql.connect(host=host, user=user, passwd=psd, db=db, charset=c, port=port)
# 数据库游标
cue = con.cursor()
print("mysql connect succes") # 测试语句,这在程序执行时非常有效的理解程序是否执行到这一步
try:
cue.execute("insert into news (name,content) values(%s,%s)",
[item['starname'], item['content']])
print("insert success") # 测试语句
except Exception as e:
print('Insert error:', e)
con.rollback()
else:
con.commit()
con.close()
return item
class HupuImagesPipeline(ImagesPipeline):
# 重写ImagesPipeline类的此方法
# 发送图片下载请求
def get_media_requests(self, item, info):
image_url = item["imageurl"]
str = image_url.split(',')
for i in range(1, len(str)-1):
yield scrapy.Request("http:"+str[i])
# 重写item_completed方法
# 将下载的文件保存到不同的目录中
def item_completed(self, results, item, info):
# 从项目设置文件中导入图片下载路径
IMAGES_STORE = get_project_settings().get("IMAGES_STORE")
# 固定写法,获取图片路径,同时判断这个路径是否正确,如果正确,
for i in range(0,len(results)):
os.rename(IMAGES_STORE + '/' + results[i][1]['path'], IMAGES_STORE + '/' + item['starname'] + str(i) + '.jpg')
shutil.move(IMAGES_STORE + '/' + item['starname'] + str(i) +'.jpg', './今日明星' + '/' + item['starname'])
def __del__(self):
IMAGES_STORE = get_project_settings().get("IMAGES_STORE")
# 完成后删除整个full目录
shutil.rmtree(IMAGES_STORE + '/' + 'full')
shutil.rmtree(IMAGES_STORE)
5.8.1 创建 txt 代码
filename = item['contenttitle']
filename += ".txt"
# 个人简介放到个人相对应的文件夹中
savepath='./今日明星'+'/'+item['starname']+'/'+filename
fp = open(savepath, 'w', encoding='utf-8')
fp.write(item['content'])
fp.close()
5.8.2 图片下载的代码
# 重写ImagesPipeline类的此方法
# 发送图片下载请求
def get_media_requests(self, item, info):
image_url = item["imageurl"]
str = image_url.split(',')
for i in range(1, len(str)-1):
yield scrapy.Request("http:"+str[i])
# 重写item_completed方法
# 将下载的文件保存到不同的目录中
def item_completed(self, results, item, info):
# 从项目设置文件中导入图片下载路径
IMAGES_STORE = get_project_settings().get("IMAGES_STORE")
# 固定写法,获取图片路径,同时判断这个路径是否正确,如果正确,
for i in range(0,len(results)):
os.rename(IMAGES_STORE + '/' + results[i][1]['path'], IMAGES_STORE + '/' + item['starname'] + str(i) + '.jpg')
shutil.move(IMAGES_STORE + '/' + item['starname'] + str(i) +'.jpg', './今日明星' + '/' + item['starname'])
def __del__(self):
IMAGES_STORE = get_project_settings().get("IMAGES_STORE")
# 完成后删除整个full目录
shutil.rmtree(IMAGES_STORE + '/' + 'full')
shutil.rmtree(IMAGES_STORE)
5.8.3 数据上传到 mysql
host = '127.0.0.1'
user = 'root'
psd = 'root'
db = "python"
c = "utf8"
port = 3306
# 数据库连接
con = pymysql.connect(host=host, user=user, passwd=psd, db=db, charset=c, port=port)
# 数据库游标
cue = con.cursor()
print("mysql connect succes") # 测试语句,这在程序执行时非常有效的理解程序是否执行到这一步
try:
cue.execute("insert into news (name,content) values(%s,%s)",
[item['starname'], item['content']])
print("insert success") # 测试语句
except Exception as e:
print('Insert error:', e)
con.rollback()
else:
con.commit()
con.close()
六、效果展示
6.1
6.2
参考
http://www.runoob.com/python/python-tutorial.html
https://scrapy-chs.readthedocs.io/zh_CN/1.0/intro/overview.html