自从毕设开始搞了Python之后就觉得这个东西值得研究。
但是毕设的东西非常的浅显,个人觉得最值得训练的还是Python的爬虫,谨以此开篇,作为学习和练习Python的起步。
——————————学习分割线————————————
第一次学习的是Python爬取图片信息。
网上有很多很多关于这一类东西的教程,我也仅仅是可以实现,并且停留在一知半解的程度,在代码过程中添加了很多对Python的新的理解,对编程这个大集合的更深层的理解。
网上的任何东西都可以看成资源,一个网站可能就是一段html+css,一张图片可能就是某个地址下的XXX.jpg文件,无数的网络资源存放在互联网上,人们通过地址(URL,统一资源定位符)来访问这些资源,大致过程如下:
用户在浏览器中输入访问地址,浏览器向服务器发送HTTP(或者HTTPS)请求(其中请求资源常用get请求,提交数据常用post请求,post也可做数据请求)。服务器接收到了这些请求之后找到对应的资源返回给浏览器,再经过浏览器的解析,最终呈现在用户面前。
这就是用户上网的一个简单的过程。那么,如果我们需要大量的从网上请求数据,依靠人工一个个得机械操作显然是不现实的,这时候爬虫就起作用了。
一开始先要搞清楚什么是爬虫。
其实本质上来说爬虫就是一段程序代码。任何程序语言都可以做爬虫,只是繁简程度不同而已。从定义上来说,爬虫就是模拟用户自动浏览并且保存网络数据的程序,当然,大部分的爬虫都是爬取网页信息(文本,图片,媒体流)。但是人家维护网站的人也不是傻的,大量的用户访问请求可以视为对服务器的攻击,这时候就要采取一些反爬机制来及时阻止人们的不知道是善意的还是恶意的大量访问请求(当然了= =不这样人家服务器吃枣爆炸)。
网站爬取过程中我们会碰到以下几种情况:
1.直接加载资源无处理
2.使用ajax异步加载
3.带参数验证的加载
4.cookie验证
5.登录验证
6.js加密
第一种无需解释,第二种是用户访问过程中异步向服务器发送请求会给筛选爬取数据增加难度,第三种是参数验证例例如时间戳,ip等,第四种是追踪验证用户的本地数据,第五种是身份验证,第六种是加载后对数据进行加密操作增加爬取难度。
本次学习只处理到第三层,带参数验证的网站加载。
学习时爬取的是这个网站(如有打扰,十分抱歉)http://tu.duowan.com/m/bizhi
先对这个网站进行分析。大部分都是套图,有一张图作为封面,并且,点击进入图片之后,有一个显示第一张图片的链接。
那么我们第一步可以在主界面的html代码中抽取出这些套图起始的链接地址,这里显然需要用到正则来提取这些不同地址。
那么,有了每个套图的起始地址之后,我们进入到子页面,刷新网页,观察它的加载流程。
这里我们可以观察到,仅仅是一张图片的加载就进行了如此多的工作,这个网站相对来说还是很复杂的(以后会放上一些相对来说不复杂的网页对比非常明显)
这里我们点击XHR,会发现chrome自动为我们筛选出了一个XHR对象,这是其使用ajax技术的证明,点击之后我们发现里边带的json数据跟我们想要的套图信息其实是一致的
随意点开一个发现里边的信息都是键值对的形式存在着,这里我们发现source一栏,选定该地址新建标签访问
这就是这张图片在网络上的地址(URL,统一资源定位符)
至此分析全部结束。
我们需要理清楚我们到底要做什么。
1.抓取主页面HTML代码,筛选出所有的套图链接
2.从套图页面中获取json,从信息中获取该套图的全部URL
3.根据URL下载图片到本地
4.重复2,3
下面挂上一个学习使用的代码
import json
import os
import re
import time
import requests
import pymysql
def strip(path):
path = re.sub(r'[?\\*|"<>:/]', '', str(path))
return path
# 爬虫类
class Spider:
#初始化函数
def __init__(self):
self.session = requests.session()
# 下载图片
def download(self, url):
try:
return self.session.get(url)
except Exception as e:
print(e)
# 从start_url开始获取全部的套图入口,并逐个获取套图信息,最终保存图片
def run(self, start_url):
#获取全部的套图入口id
img_ids = self.get_img_ids(start_url)
print(img_ids)
#并逐个获取套图信息,最终保存图片
for img_id in img_ids:
#获取套图json信息
img_item_info = self.get_img_item_info(img_id)
print(img_item_info)
self.save_img(img_item_info)
#exit()#仅循环一次
# 下载html代码,并从中筛选出套图入口id,返回套图id列表
def get_img_ids(self, start_url):
response = self.download(start_url)
if response:
html = response.text
#正则仍然有待学习
ids = re.findall(r'http://tu.duowan.com/gallery/(\d+).html', html)
return ids
# 为了拿到json数据,我们观察文件中存在两个数字,一个是套图入口id我们已知,另一个是时间戳,可以仿制
def get_img_item_info(self, img_id):
# http://tu.duowan.com/index.php?r=show/getByGallery/&gid=125658&_=1519643852451
img_item_url = "http://tu.duowan.com/index.php?r=show/getByGallery/&gid={}&_={}".format(img_id,
int(time.time() * 1000))
#下载后解析得到可用的json数据
response = self.download(img_item_url)
if response:
return json.loads(response.text)
# 套图信息持久化
def save_img(self,img_item_info):
#以套图标题创建文件夹保存套图
dir_name = img_item_info['gallery_title']
#字符串剪切去掉无法做文件夹的字符串
strip(dir_name)
print(dir_name)
#创建文件夹
if not os.path.exists(dir_name):
os.makedirs(dir_name)
#获取图片名,图片url,图片后缀,保存图片路径等
for img_info in img_item_info['picInfo']:
img_name = img_info['title']
strip(img_name)
img_url = img_info['url']
pix = (img_url.split('/')[-1]).split('.')[-1]
img_path = os.path.join(dir_name, "{}.{}".format(img_name, pix))#此处路径拼接避免出现字符串问题
print(dir_name,img_name,img_path)
#保存图片至本地
if not os.path.exists(img_path):
response = self.download(img_url)
if response:
print(img_url)
img_data = response.content
with open(img_path, 'wb') as f:
f.write(img_data)
#在本地数据库中插入记录
db = pymysql.connect("localhost", "root", "123456", "python", use_unicode=True,
charset="utf8"); # 此处会出现编码问题
cursor = db.cursor()
try:
sql = "INSERT INTO img (dir_name,img_title,img_path) VALUE (%s,%s,%s);" # 此处写法可以避免转义问题
cursor.execute(sql, (dir_name, img_name, img_path))
db.commit()
except Exception as e:
print(e)
db.rollback()
db.close()
if __name__ == '__main__':
spider = Spider()
spider.run('http://tu.duowan.com/m/bizhi')
#spider.download('http://tu.duowan.com/gallery')
代码仅供学习参考使用,也是给自己起一个回顾的作用。
代码中仍然存在缺陷,例如数据库开关操作过多等,以后的优化后期再做处理。
时常提醒自己多多练习Python。