python - 如何使用“请求”模块python进行简单的快速请求?
问题描述
我是python的初学者,我只是想用模块requests
和BeautifulSoup
这个网站我提出请求。
和我的简单代码:
import requests, time, re, json
from bs4 import BeautifulSoup as BS
url = "https://www.jobstreet.co.id/en/job-search/job-vacancy.php?ojs=6"
def list_jobs():
try:
with requests.session() as s:
st = time.time()
s.headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:57.0) Gecko/20100101 Firefox/57.0'}
req = s.get(url)
soup = BS(req.text,'html.parser')
attr = soup.findAll('div',class_='position-title header-text')
pttr = r".?(.*)Rank=\d+"
lists = {"status":200,"result":[]}
for a in attr:
sr = re.search(pttr, a.find("a")["href"])
if sr:
title = a.find('a')['title'].replace("Lihat detil lowongan -","").replace("\r","").replace("\n","")
url = a.find('a')['href']
lists["result"].append({
"title":title,
"url":url,
"detail":detail_jobs(url)
})
print(json.dumps(lists, indent=4))
end = time.time() - st
print(f"\n{end} second")
except:
pass
def detail_jobs(find_url):
try:
with requests.session() as s:
s.headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:57.0) Gecko/20100101 Firefox/57.0'}
req = s.get(find_url)
soup = BS(req.text,'html.parser')
position = soup.find('h1',class_='job-position').text
name = soup.find('div',class_='company_name').text.strip("\t")
try:
addrs = soup.find('div',class_='map-col-wraper').find('p',{'id':'address'}).text
except Exception:
addrs = "Unknown"
try:
loct = soup.find('span',{'id':'single_work_location'}).text
except Exception:
loct = soup.find('span',{'id':'multiple_work_location_list'}).find('span',{'class':'show'}).text
dests = soup.findAll('div',attrs={'id':'job_description'})
for select in dests:
txt = select.text if not select.text.startswith("\n") or not select.text.endswith("\n") else select.text.replace("\n","")
result = {
"name":name,
"location":loct,
"position":position,
"description":txt,
"address":addrs
}
return result
except:
pass
他们都运作良好,但需要很长时间才能显示结果时间总是高于 13/17 秒
我不知道如何提高我的请求速度
我尝试在堆栈和谷歌上搜索,他们说使用 asyncio 但对我来说太难了。
如果有人有简单的技巧如何通过简单的操作来提高速度,我很感激..
对不起我的英语不好
解决方案
通过网页抓取等项目学习 Python 非常棒。这就是我被介绍给 Python 的方式。也就是说,为了提高抓取速度,您可以做三件事:
- 将 html 解析器更改为更快的东西。'html.parser' 是其中最慢的。尝试更改为“lxml”或“html5lib”。(阅读https://www.crummy.com/software/BeautifulSoup/bs4/doc/)
删除循环和正则表达式,因为它们会减慢您的脚本。只需使用 BeautifulSoup 工具、文本和条带,并找到正确的标签。(见下面我的脚本)
由于网页抓取的瓶颈通常是 IO,等待从网页获取数据,使用异步或多线程将提高速度。在下面的脚本中,我使用了多线程。目的是同时从多个页面中提取数据。
因此,如果我们知道最大页面数,我们可以将我们的请求分成不同的范围并分批提取它们:)
代码示例:
from collections import defaultdict
from concurrent.futures import ThreadPoolExecutor
from datetime import datetime
import requests
from bs4 import BeautifulSoup as bs
data = defaultdict(list)
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:57.0) Gecko/20100101 Firefox/57.0'}
def get_data(data, headers, page=1):
# Get start time
start_time = datetime.now()
url = f'https://www.jobstreet.co.id/en/job-search/job-vacancy/{page}/?src=20&srcr=2000&ojs=6'
r = requests.get(url, headers=headers)
# If the requests is fine, proceed
if r.ok:
jobs = bs(r.content,'lxml').find('div',{'id':'job_listing_panel'})
data['title'].extend([i.text.strip() for i in jobs.find_all('div',{'class':'position-title header-text'})])
data['company'].extend([i.text.strip() for i in jobs.find_all('h3',{'class':'company-name'})])
data['location'].extend([i['title'] for i in jobs.find_all('li',{'class':'job-location'})] )
data['desc'].extend([i.text.strip() for i in jobs.find_all('ul',{'class':'list-unstyled hidden-xs '})])
else:
print('connection issues')
print(f'Page: {page} | Time taken {datetime.now()-start_time}')
return data
def multi_get_data(data,headers,start_page=1,end_page=20,workers=20):
start_time = datetime.now()
# Execute our get_data in multiple threads each having a different page number
with ThreadPoolExecutor(max_workers=workers) as executor:
[executor.submit(get_data, data=data,headers=headers,page=i) for i in range(start_page,end_page+1)]
print(f'Page {start_page}-{end_page} | Time take {datetime.now() - start_time}')
return data
# Test page 10-15
k = multi_get_data(data,headers,start_page=10,end_page=15)
解释 multi_get_data 函数:
此函数将在不同线程中调用 get_data 函数并传递所需的参数。目前,每个线程都有一个不同的页码来调用。最大工作线程数设置为 20,即 20 个线程。您可以相应地增加或减少。
我们创建了可变数据,一个默认字典,它包含列表。所有线程都将填充此数据。然后可以将此变量转换为 json 或 Pandas DataFrame :)
如您所见,我们有 5 个请求,每个请求用时不到 2 秒,但总数仍不到 2 秒;)
享受网页抓取。
更新_:22/12/2019
我们还可以通过使用带有单个标头更新的会话来获得一些速度。所以我们不必在每次通话时都开始会话。
from requests import Session
s = Session()
headers = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) '\
'AppleWebKit/537.36 (KHTML, like Gecko) '\
'Chrome/75.0.3770.80 Safari/537.36'}
# Add headers
s.headers.update(headers)
# we can use s as we do requests
# s.get(...)
...
推荐阅读
- javascript - 如何将 javascript 字符串转换为 Razor 方法中的参数?
- python-3.x - 如何使用 matplotlib.pyplot.barh 更改条形位置
- php - 如何在角度数据表中获取数据?
- regex - 正则表达式检查字符串中出现的多个字符
- ios - Swift Navigationbar 搜索栏在单击时关闭搜索文本
- javascript - 如何在页面之间/跨页面传递/发送状态?
- azure - Microsoft graph 在订阅第 12 组订阅的通知 API 时出现 403 Forbidden 错误
- ios - 使用 UIBezierPath 在 2 点之间绘制波浪
- c++ - 为什么 C++ 关联容器谓词默认不透明?
- qualtrics - 联系参与者反应的方法