day 7-多线程技术
1.字体反爬
import requests
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36'
}
code = {
'0xE1D0': '8',
'0xE325': '2',
'0xE41D': '3',
'0xe52e': '4',
'0xe630': '5',
'0xe76e': '7',
'0xe891': '1',
'0xe9ce': '0',
'0xeaf2': '9',
'0xec4c': '6'
}
new_code = dict((f'&#{eval(x)}', code[x]) for x in code)
# print(new_code)
url = 'https://mapi.guazi.com/car-source/carList/pcList?osv=IOS&minor=&sourceType=&ec_buy_car_list_ab=&location_city=&district_id=&tag=-1&license_date=&auto_type=&driving_type=&gearbox=&road_haul=&air_displacement=&emission=&car_color=&guobie=&bright_spot_config=&seat=&fuel_type=&order=&priceRange=0,-1&tag_types=&diff_city=&intention_options=&initialPriceRange=&monthlyPriceRange=&transfer_num=&car_year=&carid_qigangshu=&carid_jinqixingshi=&cheliangjibie=&page=1&pageSize=20&city_filter=12&city=12&guazi_city=12&qpres=&platfromSource=wap&versionId=0.0.0.0&sourceFrom=wap&deviceId=d9217098-1286-47a7-af41-d0e4644a52f8'
response = requests.get(url, headers=headers)
result = response.json()
for x in result['data']['postList']:
first_pay = x['first_pay'].split(';')
new_first_pay = []
for i in first_pay:
if i in new_code:
new_first_pay.append(new_code[i])
elif i[1:] in new_code:
new_first_pay.append('.' + new_code[i[1:]])
else:
new_first_pay.append(i)
first_pay = ''.join(new_first_pay)
print(first_pay)
2.认识多线程和多进程
1.什么是进程
一个正在运行的应用程序就是一个进程
进程是系统分配内容的最小单位。
每个进程均运行在其专门且受保护的内存空间中,当进程结束的时候,这个进程对应的内存空间会自动释放。
2.线程
线程是进程执行任务的基本单元。
进程中的任务都在线程中执行的(如果一个进程中没有线程,那么这个进程对应的程序什么事情都做不了)。
进程 - 车间(工厂), 提供厂房以及厂房中保存资源
线程 - 车间工人
默认情况下,一个进程中有一个线程。
3.多线程
一个进程中有多个线程
单线程特点:一个线程执行多个任务,只能串行(一个一个按顺序)执行。
多线程特点:多个线程执行多个任务,可以并行(同时)执行。
单线程 - 一个工厂中只有一个工人
多线程 - 一个工厂中同时有多个工人,多线程的存在可以提高程序的效率。
手机应用程序:3 ~ 5线程
电脑应用程序:200 ~ 300个
4.多线程的原理
一个cpu同一时间只能处理一个线程,同一时间只有一个线程可以工作。
多线程的原理: 多线程技术其实就是利用CPU空闲时间做其他事情。
3.使用多线程
import time
from datetime import datetime
from threading import Thread, current_thread
1.主线程和子线程
一个进程默认只有一个线程,这个线程就是主线程,除了主线程以外的线程都是子线程。
子线程需要由程序员自己创建
什么时候需要子线程,什么时候就创建线程对象: Thread - 线程类
def download(name):
print(f'======{name}开始下载:{datetime.now()}======')
print(current_thread())
time.sleep(2)
print(f'======{name}下载结束:{datetime.now()}======')
if __name__ == '__main__':
# 方案1:在主线程中直接下载三个电影
# download('肖申克的救赎')
# download('霸王别姬')
# download('阿甘正传')
# 方案2:在三个子线程中分别下载三个电影
# 1)创建线程对象: Thread(*,target=函数, args=元组)
# target: 需要在子线程中执行的任务(以函数的形式提供)
# args: 元组中的元素就是在调用target对应的函数的时候的实参
t1 = Thread(target=download, args=('肖申克的救赎',))
t2 = Thread(target=download, args=('霸王别姬',))
t3 = Thread(target=download, args=('阿甘正传',))
# 2)启动线程 - 在子线程中调用target对应的函数,参数就传args中的数据
# 线程对象.start()
t1.start()
t2.start()
t3.start()
4.多线程获取豆瓣电影数据
import requests
from lxml import etree
from re import sub
import csv
from threading import Thread
def get_page_data(page):
print(f'第{page//25}页数据开始下载')
# 1.获取网页数据
url = f'https://movie.douban.com/top250?start={page}&filter='
headers = {
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36',
'cookie': 'bid=2L4tF88mhxQ; ll="118318"; dbcl2="222590700:FVo7RHfVAd4"; ck=P4n_; push_noty_num=0; push_doumail_num=0'
}
response = requests.get(url, headers=headers)
# 2. 使用xpath解析数据
root = etree.HTML(response.text)
all_div = root.xpath('//ol[@class="grid_view"]/li/div')
all_data = []
for div in all_div:
# 电影名字
name = div.xpath('./div/div[@class="hd"]/a/span[1]/text()')[0]
# 电影其他信息
info = div.xpath('./div/div[@class="bd"]/p[1]/text()')[1].strip().split('/')
time = sub(r'\s+', '', info[0])
country = sub(r'\s+', '', info[1])
movie_type = info[-1][1:].replace(' ', ',')
# 评分
score = div.xpath('./div/div[@class="bd"]/div/span[@class="rating_num"]/text()')[0]
all_data.append([name, score, time, country, movie_type])
# 3.保存数据
writer.writerows(all_data)
print(f'第{page//25}页数据下载完成!')
if __name__ == '__main__':
writer = csv.writer(open('files/电影.csv', 'w', encoding='utf-8', newline=''))
writer.writerow(['电影名称', '评分', '上映时间', '国家', '类型'])
for x in range(0, 226, 25):
t = Thread(target=get_page_data, args=(x, ))
t.start()
5.阻塞
import time
from datetime import datetime
from threading import Thread, current_thread
from random import randint
# 定义download函数
def download(name):
print(f'======{name}开始下载:{datetime.now()}======')
time.sleep(randint(2, 7))
print(f'======{name}下载结束:{datetime.now()}======')
if __name__ == '__main__':
# 创建三个子线程分别下载三个电影
# t1 = Thread(target=download, args=('肖申克的救赎',))
# t2 = Thread(target=download, args=('霸王别姬',))
# t3 = Thread(target=download, args=('阿甘正传',))
# 案例1:三个电影同时开始下载,所有电影都下载结束后才打印"全部下载完成"
# t1.start()
# t2.start()
# t3.start()
#
# # 1.线程对象.join() - 让当前线程处于阻塞状态,直到指定线程对应的任务完成位置
# t1.join()
# t2.join()
# t3.join()
#
# print('全部下载完成!')
# 案例2: 等第1个电影下载完成,才同时下载第2个和第3个电影
# t1.start()
#
# t1.join()
# t2.start()
# t3.start()
# 练习:同时下载20部电影,电影1、电影2、电影3,....、电影20,要求所有电影都下载结束后打印 '全部下载完成!'
ts = []
for x in range(1, 21):
name = f'电影{x}'
t = Thread(target=download, args=(name,))
t.start()
ts.append(t)
for t in ts:
t.join()
print('全部下载完成!')
6.获取豆瓣优化
import requests
from lxml import etree
from re import sub
import csv
from threading import Thread
def get_page_data(page):
print(f'第{page//25}页数据开始下载')
# 1.获取网页数据
url = f'https://movie.douban.com/top250?start={page}&filter='
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36',
'cookie': 'bid=2L4tF88mhxQ; ll="118318"; dbcl2="222590700:FVo7RHfVAd4"; ck=P4n_; push_noty_num=0; push_doumail_num=0'
}
proxy = {
'https': '119.7.145.186:4531',
'http': '119.7.145.186:4531'
}
response = requests.get(url, headers=headers, proxies=proxy)
print(response.text)
# 2. 使用xpath解析数据
root = etree.HTML(response.text)
all_div = root.xpath('//ol[@class="grid_view"]/li/div')
page_data = []
for div in all_div:
# 电影名字
name = div.xpath('./div/div[@class="hd"]/a/span[1]/text()')[0]
# 电影其他信息
info = div.xpath('./div/div[@class="bd"]/p[1]/text()')[1].strip().split('/')
time = sub(r'\s+', '', info[0])
country = sub(r'\s+', '', info[1])
movie_type = info[-1][1:].replace(' ', ',')
# 评分
score = div.xpath('./div/div[@class="bd"]/div/span[@class="rating_num"]/text()')[0]
# 排名
rank = div.xpath('./div/em/text()')[0]
page_data.append([int(rank), name, score, time, country, movie_type])
all_data.append((page, page_data))
if __name__ == '__main__':
writer = csv.writer(open('files/电影.csv', 'w', encoding='utf-8', newline=''))
writer.writerow(['排名','电影名称', '评分', '上映时间', '国家', '类型'])
all_data = []
ts = []
for x in range(0, 226, 25):
t = Thread(target=get_page_data, args=(x, ))
t.start()
ts.append(t)
for t in ts:
t.join()
# all_data = [(页数, [[], [], [], []]), (页数, [[], [], [], []]), (页数, [[], [], [], []]),...]
all_data.sort(key=lambda item: item[0])
for x in all_data:
writer.writerows(x[1])