这几天在看《python3 网络爬虫实战》,里面用到了tesseract和它对应的语言包,为了避免使用这个库出错,我就开始在github上下载对应的语言包,但是无论是使用浏览器,还是wget下载,都会在下载一大半的时候出错,于是萌生了一个分开下载的念头。转念一想,自己手动根据链接下载比较简单,但是麻烦,而且重复;而恰好正在学习爬虫的相关知识,因此有了下面的代码。
本示例代码爬取了https://github.com/tesseract-ocr/tessdata这个网址的所有有效下载链接,之后下载所有链接,并放置在当前目录下的save文件夹下。
示例代码采用python3,用到的主要是requests和pyquery;前者负责获取源码,后者则是用来css解析。
下图是我的成果:
总共1000多M,因为实验室的网络一如既往地稳定地差,所以总是下载失败。
首先大致说一下导入的模块:
import requests
from pyquery import PyQuery as pq
from urllib.parse import urljoin
from multiprocessing.pool import Pool
import os
1.requests 负责模拟浏览器发送请求,并获得响应,然后从响应中获得html文本。
2.pyquery 负责解析html文本,获取有用的标签中的文本或属性。
3.urllib.parse 仅仅用到了urljoin这个函数,负责给链接添加协议或者是域名。
4.os 负责创建save文件夹,以及把下载的文件保存到save文件夹下。
5.multiprocessing 多线程。
base_url = 'https://github.com'
def get_items_from_url(url):
'''
从url中获取html文本,解析后返回dict
@param url 要解析的链接
@return dict {'name' : '文件名', 'url' : '下载链接'}
'''
headers = {
'Host' : 'github.com',
'User-Agent' : 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36',
}
response = requests.get(url = url, headers = headers)
#响应失败,则直接返回
if response.status_code != 200:
print('网页加载错误')
return
#开始解析标签
doc = pq(response.text)
items = doc.find('tr.js-navigation-item').items()
for item in items:
a = item.find('.content span a')
name = a.text()
#排除不必要的链接
if name.find('traineddata') == -1:
continue
yield {
'name' : name,
'url' : urljoin(base_url, a.attr('href').replace('blob', 'raw'))
}
get_items_from_url()用来解析链接对应的html文本,获取有用的信息,在本示例下为文件名称和对应的下载链接。
注意requests.get()中添加了一个请求头,这个一般是用来模拟浏览器的;获取响应后判断了状态码即status_code是否为200(成功),不成功则直接退出;最后urljoin()函数则是给一些不存在协议或域名的链接加上缺失的部分。
def download_file(dic):
'''
下载文件
@param dic {'name' : '文件名', 'url' : '链接'}
'''
name = dic['name']
url = dic['url']
#保证save文件夹存在
if not os.path.exists('save'):
os.path.mkdir('save')
print('Ready download %s' % name)
#开始下载
try:
response = requests.get(url)
file_path = 'save/{0}'.format(name)
if not os.path.exists(file_path):
with open(file_path, 'wb') as f:
f.write(response.content)
print('Successfully download %s' % name)
else:
print('%s already downloaded' % name)
except requests.ConnectionError:
print('Failed download %s' % name)
在download_file()函数中,通过调用requests.get()来下载文件。
另外注意这里用的是response.content而不是response.text 注:text获取的是字符串,而content则是字节流。
最后则是对上面两个函数的调用了。
if __name__ == '__main__':
#要下载的链接
url = 'https://github.com/tesseract-ocr/tessdata'
#解析完成的项列表
groups = []
for item in get_items_from_url(url):
groups.append(item)
print('parse data success!!!')
#多线程下载
pool = Pool()
pool.map(download_file, groups)
pool.close()
pool.join()
这部分则比较简单,先通过get_items_from_url()获取所有的链接,然后多线程下载文件。当下载完成后,程序结束。