Как сделать простой быстрый запрос с «запросами» модуля python? - PullRequest
0 голосов
/ 12 января 2019

Я новичок в 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 секунд

Я не знаю, как увеличить мою скорость для запроса

Я попробовал поиск в стеке и в Google, они сказали, что используют asyncio, но мне так трудно.

Если у кого-то есть простой трюк, как увеличить скорость с помощью простого do, я так ценю ..

И извините за мой плохой английский

Ответы [ 4 ]

0 голосов
/ 12 января 2019

Изучение Python с помощью таких проектов, как утилизация в сети, потрясающе. Вот как я познакомился с Python. Тем не менее, чтобы увеличить скорость утилизации, вы можете сделать три вещи:

  1. Измените анализатор HTML на что-то более быстрое. html.parser - самый медленный из них. Попробуйте изменить на «lxml» или «html5lib». (читай https://www.crummy.com/software/BeautifulSoup/bs4/doc/)

enter image description here

  1. Удалите циклы и регулярные выражения, поскольку они замедляют ваш сценарий. Просто используйте инструменты BeautifulSoup, текст и полоску и найдите нужные теги (см. Мой скрипт ниже)

  2. Поскольку узким местом в удалении веб-страниц обычно является ввод-вывод, ожидание получения данных с веб-страницы с использованием асинхронной или многопоточной обработки увеличит скорость. В приведенном ниже сценарии я использую многопоточность. Цель состоит в том, чтобы извлекать данные с нескольких страниц одновременно.

Так что, если мы знаем максимальное количество страниц, мы можем разделить наши запросы на несколько диапазонов и распределить их по пакетам :)

Пример кода:

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)

Результаты: enter image description here

Объяснение функции multi_get_data:

Эта функция будет вызывать функцию get_data в разных потоках с передачей нужных аргументов. На данный момент каждая ветка получает свой номер страницы для звонка. Максимальное количество рабочих установлено в 20, что означает 20 потоков. Вы можете увеличить или уменьшить соответственно.

Мы создали переменные данные, словарь по умолчанию, который принимает списки. Все потоки будут заполнять эти данные. Затем эту переменную можно преобразовать в json или Pandas DataFrame:)

Как вы видите, у нас есть 5 запросов, каждый из которых занимает менее 2 секунд, но общее количество по-прежнему меньше 2 секунд;)

Наслаждайтесь просмотром веб-страниц.

0 голосов
/ 12 января 2019

Это мое предложение написать код с хорошей архитектурой, разделить его на функции и написать меньше кода. Это один из примеров использования запроса:

from requests import get
from requests.exceptions import RequestException
from contextlib import closing
from bs4 import BeautifulSoup

def simple_get(url):
    """
    Attempts to get the content at `url` by making an HTTP GET request.
    If the content-type of response is some kind of HTML/XML, return the
    text content, otherwise return None.
    """
    try:
        with closing(get(url, stream=True)) as resp:
            if is_good_response(resp):
                return resp.content
            else:
                return None

    except RequestException as e:
        log_error('Error during requests to {0} : {1}'.format(url, str(e)))
        return None


def is_good_response(resp):
    """
    Returns True if the response seems to be HTML, False otherwise.
    """
    content_type = resp.headers['Content-Type'].lower()
    return (resp.status_code == 200 
            and content_type is not None 
            and content_type.find('html') > -1)


def log_error(e):
    """
    It is always a good idea to log errors. 
    This function just prints them, but you can
    make it do anything.
    """
    print(e)

Отладьте ваш код по тем пунктам, которые требуют времени, выясните их и обсудите здесь. Это поможет вам решить вашу проблему.

0 голосов
/ 12 января 2019

Попробуйте использовать scrapy , он будет обрабатывать общение на сайте (запрос / ответ) для вас.

Если вы сделаете много запросов, вы будете заблокированы, они используют Cloudflare products

0 голосов
/ 12 января 2019

Узким местом является сервер, медленно реагирующий на простые запросы.

Попробуйте выполнить запрос параллельно.

Вы также можете использовать темы вместо asyncio. Вот предыдущий вопрос, поясняющий для задач параллелизма в Python:

Выполнение задач параллельно в python

Обратите внимание, что правильно настроенный сервер будет по-прежнему замедлять ваши запросы или блокировать вас, если вы очищаете без разрешения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...