前言
好久没更新博客了,最近来一波更新吧。
咳咳,最近得到了一批纯洁图片的 url 地址,起因是有人用爬虫爬取纯洁网站的图片。刚好很久没折腾了,于是我想着使用 python 脚本,把它们都下载下来。
第一个简单的版本:单进程下载
话不多说,直接上代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| import sqlite3 import urllib.request
conn = sqlite3.connect('seePicture.db') cursor = conn.cursor() cursor.execute('select * from picture')
values = cursor.fetchall()
cursor.close() conn.close()
imgName = 0 li = [] head = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'
for t in values: url = t[3] li.append(url)
def get_content(pic_url, headers): req = urllib.request.Request(pic_url) req.add_header("User-Agent", headers)
content = urllib.request.urlopen(req).read() return content
for url in li: try: f = open('D:\\Temp\\pic\\' + str(imgName) + '.jpg', 'wb') c = get_content(url, head) f.write(c) print(url + ' ok') f.close() except Exception as e: print(url + ' error') print(e) imgName += 1
print("All Done!")
|
简单解释一下,这个直接就是从 sqlite 中取出所有数据,因为本身数据量就不大,我看了下就一千多条记录,可以一次性全部取出。将取出的记录中的第 4 个字段,也就是图片地址那个字段取出来,组成一个新的 list。然后就是对这个 list 进行遍历,将它下载保存到D:\Temp\pic
中。
刚开始我直接下载的时候我看报错信息是HTTP Error 403: Forbidden
,于是我加上了请求头User-Agent
,然后就能正常请求下载了。
第二个版本:使用多进程,提高下载速度
第一个版本里面,使用的是本地的 sqlite 数据库,其实就是一个几十 k 的文件,图片太少了。
然后我要到了数据库,看了下将近两百万条,这个应该够看了。跟上面相比只是连接的数据库不一样了,其他的都一样。
但是这样存在一个问题,就是下载太慢了,因为毕竟是单线程下载。然后我在网上看了好几份代码,结合了一下,同时修改了代码结构,整出一个多进程的版本,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| import requests import pymysql from multiprocessing import Pool import datetime
class Spider:
@staticmethod def get_list(): db = pymysql.connect(host="192.168.1.1", user="root", password="root", db="db", port=3306) cur = db.cursor() sql = "SELECT * FROM picture WHERE id > 0 LIMIT 4000" try: cur.execute(sql) results = cur.fetchall() finally: db.close() url_list = [] for t in results: url = t[2] url_list.append(url) return url_list
@staticmethod def get_pic(pic_url, file_name): try: resource = requests.get(pic_url) with open(file_name, 'wb') as file: file.write(resource.content) print(pic_url + " ok") except Exception as e: print(pic_url + " error") print(e)
if __name__ == "__main__": spider = Spider() urls = spider.get_list() p = Pool(40) d1 = datetime.datetime.now() j = 0
for i in urls: p.apply_async(spider.get_pic, args=(i, 'D:\\Temp\\pic\\' + str(j) + '.jpg')) j += 1
p.close() p.join() d2 = datetime.datetime.now() print(d2 - d1) print("All Done!")
|
上述代码主要是使用了多进程来执行任务,从而加快执行的速度。使用上述代码之后,我发现下载图片的速度相比原来大大提高,一下子就能下载好多张。
第三个版本:直接命令行启动
有了上述版本之后,其实就已经能正常使用了,但是由于我是通过 ide,也就是 PyCharm 直接启动的,如果日常使用的话,会十分不方便。然后我就对它改造了一下,使得这个脚本直接可以在命令行里面启动,启动的时候给个参数就行。
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| import requests import pymysql from multiprocessing import Pool import datetime import sys
class Spider:
@staticmethod def get_list(num): db = pymysql.connect(host="192.168.1.1", user="root", password="root", db="db", port=3306) cur = db.cursor() sql = 'SELECT * FROM picture WHERE id > ' + num + ' LIMIT 4000' try: cur.execute(sql) results = cur.fetchall() finally: db.close() url_list = [] for t in results: url = t[2] url_list.append(url) return url_list
@staticmethod def get_pic(pic_url, file_name): try: resource = requests.get(pic_url) with open(file_name, 'wb') as file: file.write(resource.content) print(pic_url + " ok") except Exception as e: print(pic_url + " error") print(e)
if __name__ == "__main__": arg = sys.argv[1] print('传入的参数为:' + arg)
j = int(arg) + 1
spider = Spider() urls = spider.get_list(str(j)) p = Pool(40) d1 = datetime.datetime.now()
for i in urls: p.apply_async(spider.get_pic, args=(i, 'D:\\Temp\\pic\\' + str(j) + '.jpg')) j += 1
p.close() p.join() d2 = datetime.datetime.now() print(d2 - d1) print("All Done!")
|
主要是使用了sys.argv[1]
这个变量,sys.argv[0]
默认就是文件名,sys.argv[1]
就是输入的第一个参数,另外就是注意一下哪里该用整数,哪里该用字符串。
在命令行环境下,假设这个 python 脚本名字为spy.py
,启动的时候输入:
即可开始运行脚本。
注意:直接运行脚本的时候还要注意一个细节,就是引入的库是全局存在的,还是当前项目所引入的,不然可能会报ModuleNotFoundError: No module named 'XXX'
异常。