最近想把之前写的一些代码和经验写成博客记录下来,写了两篇之后我发现写博客蛮有意思的,既是对知识的一个总结,又可以提高我自己的写作能力,更重要的是自己敞开心扉与自己的一次自我审视与交流。
爬虫网站:全景网 https://www.quanjing.com/
爬取目标:根据搜索关键词爬取图片
没有分析过程的爬虫都是耍流氓。
首先进入全景网首页,F12打开谷歌开发者工具,选中network板块,在搜索栏中输入关键字如“黑人””二字,按enter键搜索,进入如下页面
观察可得知该请求即为搜索栏发出的搜索请求,然后点击Preview面板,
可以看到该请求将搜索结果页面中的所有图片的地址一并传给了浏览器,所以我们只要模拟该请求即可得到我们想要的数据,注意headers里面的信息
图片的分页在这里也有,所以我们只需要在请求参数里面带上即可。
到此为止爬虫的url和数据这些都解决了,下面要做就用多线程实现爬虫,这里我用的是concurrent.futures模块实现线程池,使用该线程的步骤如下:
#1、调用 ThreadPoolExecutor 类的构造器创建一个线程池。
#2、定义一个普通函数作为线程任务。
#3、调用 ThreadPoolExecutor 对象的 submit() 方法来提交线程任务。
#4、当不想提交任何任务时,调用 ThreadPoolExecutor 对象的 shutdown() 方法来关闭线程池。
废话不多说了,代码里面有注释
import json
import urllib
import jsonpath
import requests
import uuid
from concurrent.futures import ThreadPoolExecutor
import os
'''
全景网多线程爬虫
'''
def run(lists):
for page in range(lists[0], lists[1]+1): #dic['startNum'] dic['endNum']
params = get_params()
params['pagenum'] = page
images = request_page(get_url(), get_headers(),params)
try:
imgStr = images.replace("searchresult(", "").replace(')', '')
jsonObjs = json.loads(imgStr)
for image_url in jsonpath.jsonpath(jsonObjs,"$.imglist..imgurl"):
try:
print(lists[3] + '正在下载图片') #dic['tname']
print('')
download_pic(image_url, str(uuid.uuid1()), lists[2]) #dic['path']
except Exception as e:
print(str(e))
continue
except Exception as e:
print(str(e))
continue
def request_page(startUrl,headers,params):
try:
requests.packages.urllib3.disable_warnings()
images = requests.get(startUrl, headers=headers, params=params, verify=False, timeout=4)
if images.status_code == 200:
return images.text
except requests.RequestException:
return None
def download_pic(url,name,path):
if not os.path.exists(path):
os.makedirs(path)
try:
res=urllib.request.urlopen(url,timeout=3).read()
with open(path+name+'.jpg','wb') as file:
file.write(res)
file.close()
except Exception as e:
print(str(e))
def get_headers():
headers = {
'Accept': 'text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Connection': 'keep-alive',
'Host': 'quanjing.com',
'Referer': 'https://quanjing.com/search.aspx?',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36',
'X-Requested-With': 'XMLHttpRequest'
}
return headers
def get_params():
params = {'t': '3380', 'callback': 'searchresult',
'q': '篮球',
'stype': '1',
'pagesize': '100', 'pagenum': '3',
'imageType': '2', 'imageColor': '', 'brand': '', 'imageSType': '',
'fr': '1', 'sortFlag': '1', 'imageUType': '', 'btype': '',
'authid': '', '_': '1568595066763'
}
return params
def get_url():
return "https://quanjing.com/Handler/SearchUrl.ashx?"
if __name__ == '__main__':
# 使用线程池来执行线程任务的步骤如下:
#1、调用 ThreadPoolExecutor 类的构造器创建一个线程池。
#2、定义一个普通函数作为线程任务。
#3、调用 ThreadPoolExecutor 对象的 submit() 方法来提交线程任务。
#4、当不想提交任何任务时,调用 ThreadPoolExecutor 对象的 shutdown() 方法来关闭线程池。
lists = []
list1 = (1,2,'d:/download/全景网1/','线程A') # 1:起始页,2:结束页 ,d:/download/全景网1/:图片存储路径 线程A:线程名
list2 = (6, 7, 'd:/download/全景网1/', '线程B')
list3 = (11, 12, 'd:/download/全景网1/', '线程C')
list4 = (16, 17, 'd:/download/全景网1/', '线程D')
list5 = (21, 22, 'd:/download/全景网2/', '线程E')
lists.append(list1)
lists.append(list2)
lists.append(list3)
lists.append(list4)
lists.append(list5)
threadPool = ThreadPoolExecutor(max_workers=5)
for li in lists:
future =threadPool.submit(run,li)
threadPool.shutdown(wait=True)
print('*' * 10 + '下载完成!' + '*' * 10)
有任何疑问,均可留言或私信我交流,欢迎关注,我会持续更新博客!