请求requests 多线程.py 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. import time
  2. from datetime import datetime, timedelta
  3. import requests
  4. from requests.exceptions import Timeout
  5. import retrying
  6. import execjs
  7. from lxml import etree
  8. import json
  9. from loguru import logger
  10. import threading
  11. from queue import Queue
  12. import pandas as pd
  13. # 禁用SSL相关警告 (推荐)
  14. from requests.packages.urllib3.exceptions import InsecureRequestWarning
  15. import warnings
  16. requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
  17. warnings.filterwarnings("ignore", category=DeprecationWarning) # 可选:过滤其他警告
  18. class GK:
  19. def __init__(self):
  20. self.search_flights_api = "https://booking.jetstar.com/hk/zh/booking/search-flights"
  21. self.headers = {
  22. 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36',
  23. 'Accept-Encoding': 'gzip, deflate, br',
  24. 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
  25. 'Connection': 'keep-alive',
  26. 'Content-Type': 'application/x-www-form-urlencoded',
  27. 'accept-language': 'zh-CN,zh;q=0.9',
  28. 'cache-control': 'no-cache',
  29. 'pragma': 'no-cache',
  30. 'priority': 'u=0, i',
  31. 'referer': 'https://booking.jetstar.com/',
  32. 'sec-ch-ua': '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"',
  33. 'sec-ch-ua-mobile': '?0',
  34. 'sec-ch-ua-platform': '"Windows"',
  35. 'sec-fetch-dest': 'document',
  36. 'sec-fetch-mode': 'navigate',
  37. 'sec-fetch-site': 'same-origin',
  38. 'sec-fetch-user': '?1',
  39. 'upgrade-insecure-requests': '1'
  40. }
  41. with open('./akm逆向/逆向.js', encoding='utf-8') as f:
  42. js = f.read()
  43. self.ctx = execjs.compile(js)
  44. self.session = requests.Session()
  45. # self.ip = 100000000000
  46. # self.proxies = {
  47. # 'http': f'http://B_3351_HK___5_ss-{self.ip}:ev2pjj@proxy.renlaer.com:7778',
  48. # 'https': f'http://B_3351_HK___5_ss-{self.ip}:ev2pjj@proxy.renlaer.com:7778'
  49. # }
  50. # self.proxies = {
  51. # 'http': f'127.0.0.1:8888',
  52. # 'https': f'127.0.0.1:8888'
  53. # }
  54. self.lock = threading.Lock()
  55. self.cookies_queue = Queue(maxsize=10)
  56. self.task_queue = Queue()
  57. self.resp_data_queue = Queue()
  58. @retrying.retry(stop_max_attempt_number=3, wait_fixed=4000)
  59. def get_cookie(self):
  60. logger.debug('正在获取 cookie bm-sz...')
  61. # akm js file url
  62. akm_url = "https://booking.jetstar.com/MkuYlo/pcp/LD0/PPluEQ/1ik7QcJffXbmL53i/QTcvXmg7/KS5kC3N/VRQcB"
  63. data = {
  64. 'sensor_data': self.ctx.call('encrypt1')
  65. }
  66. response = self.session.post(akm_url, headers=self.headers, verify=False, data=data,
  67. # proxies=self.proxies
  68. )
  69. print(response.text)
  70. bmsz = response.cookies.get_dict()['bm_sz']
  71. data2 = {
  72. "sensor_data": self.ctx.call('encrypt2', bmsz)
  73. }
  74. data2 = json.dumps(data2)
  75. response2 = self.session.post(akm_url, headers=self.headers, data=data2, verify=False,
  76. )
  77. print(response2.text)
  78. print(response2.status_code)
  79. with self.lock:
  80. logger.debug(f'成功获取到 bm-sz :{bmsz}')
  81. return bmsz
  82. def get_cookie_thread(self):
  83. while True:
  84. if self.cookies_queue.qsize() < 1:
  85. new_cookie = self.get_cookie()
  86. cookies = {
  87. "bm_sz": new_cookie
  88. }
  89. self.cookies_queue.put(cookies)
  90. time.sleep(15)
  91. def gen_city(self):
  92. """提取Excel表格的城市对信息, 用set去重"""
  93. # 只读取Excel的Sheet1的航段信息, 将读取的数据存储在 df(DataFrame 对象)中。
  94. df = pd.read_excel(
  95. self.excel_path,
  96. sheet_name="Sheet1",
  97. usecols=["出发机场", "到达机场"] # 只读取 "出发机场" 和 "到达机场" 两列。
  98. )
  99. segment_info = set()
  100. segment_info.add('YNT,XIY')
  101. # 遍历 DataFrame 的每一行
  102. # for row in df.itertuples(index=True, name='Pandas'):
  103. # # 访问行中的数据
  104. # segment_info.add(row.出发机场 + ',' + row.到达机场)
  105. # logger.info(f'去重后的航段长度: {len(segment_info)}, {segment_info}')
  106. return segment_info
  107. def gen_task(self, start_date, end_date):
  108. """将每个城市对与日期组合生成独立任务, 上传到任务队列"""
  109. # 获取采集城市对
  110. # for city_code in self.gen_city():
  111. # 获取采集时间
  112. for datetime_str in self.gen_datetime(start_date, end_date):
  113. # self.task_queue.put((city_code, datetime_str))
  114. self.task_queue.put((datetime_str))
  115. @retrying.retry(stop_max_attempt_number=2)
  116. def send_get(self, url, params, cookies):
  117. response = requests.get(
  118. url,
  119. headers=self.headers, params=params, cookies=cookies,
  120. timeout=15,
  121. verify=False,
  122. )
  123. # print(response)
  124. # print(response.text)
  125. response.raise_for_status()
  126. self.cookies_queue.put(cookies)
  127. return response
  128. @retrying.retry(stop_max_attempt_number=3)
  129. def get_data(self):
  130. while True:
  131. datetime_str = self.task_queue.get()
  132. cookies = self.cookies_queue.get()
  133. params = {
  134. "s": "true",
  135. "adults": "1", # 成年人
  136. "children": "0", # 儿童
  137. "infants": "0", # 婴儿
  138. "selectedclass1": "economy", # 选择类型:经济舱
  139. "currency": "CNY", # 货币
  140. "mon": "true",
  141. "channel": "DESKTOP",
  142. "origin1": "PVG", # 出发地
  143. "destination1": "NRT", # 目的地
  144. "departuredate1": datetime_str # 出发时间
  145. }
  146. logger.info(f'正在采集 {datetime_str} 航班数据...')
  147. try:
  148. response = self.send_get(self.search_flights_api, params, cookies)
  149. self.resp_data_queue.put((datetime_str, response))
  150. except Exception as e:
  151. logger.error(e)
  152. self.task_queue.put(datetime_str)
  153. raise
  154. finally:
  155. self.task_queue.task_done()
  156. self.cookies_queue.task_done()
  157. def parse_data(self):
  158. while True:
  159. datetime_str, response = self.resp_data_queue.get()
  160. html = etree.HTML(response.text)
  161. data = html.xpath("//script[@id='bundle-data-v2']/text()")
  162. if data:
  163. json_data = json.loads(data[0])
  164. print(datetime_str, ' => ', json_data)
  165. else:
  166. logger.warning(f'{datetime_str} 当天暂无数据 / 触发验证码')
  167. print(response.text)
  168. @staticmethod
  169. def gen_datetime(start_date, end_date):
  170. current_date = datetime.strptime(start_date, '%Y-%m-%d')
  171. end_date = datetime.strptime(end_date, '%Y-%m-%d')
  172. date_list = []
  173. while current_date <= end_date:
  174. date_list.append(current_date.strftime('%Y-%m-%d')) # 转换为字符串格式存储
  175. current_date += timedelta(days=1)
  176. return date_list
  177. def run(self, start_date, end_date):
  178. thread_list = []
  179. self.gen_task(start_date, end_date)
  180. for _ in range(1):
  181. t_get_cookie = threading.Thread(target=self.get_cookie_thread)
  182. thread_list.append(t_get_cookie)
  183. for _ in range(1):
  184. t_get_data = threading.Thread(target=self.get_data)
  185. thread_list.append(t_get_data)
  186. t_parse_data = threading.Thread(target=self.parse_data)
  187. thread_list.append(t_parse_data)
  188. for t_obj in thread_list:
  189. t_obj.setDaemon(True)
  190. t_obj.start()
  191. for q in [self.task_queue, self.resp_data_queue]:
  192. q.join()
  193. if __name__ == '__main__':
  194. gk = GK()
  195. gk.run(start_date='2025-06-15', end_date='2025-06-27')