Проблема соскоба полотна при прохождении функции в качестве параметра в функции - PullRequest
0 голосов
/ 18 октября 2019

Здравствуйте, я создал две функции, которые хорошо работают, которые называются в одиночку. Но когда я пытаюсь использовать цикл for с этими функциями, у меня возникает проблема с моим параметром.

Первая функция для поиска и получения ссылки для передачи на второй.

USER_AGENT = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'}

def searchsport(terme):
        url = 'https://www.verif.com/recherche/{}/1/ca/d/?ville=null'.format(terme)
        response = requests.get(url, headers= USER_AGENT)
        response.raise_for_status()
        return terme, response.text

def crawl(keyword):    
    if __name__ == '__main__':
        try:
            keyword, html = searchsport(keyword)
            soup = bs(html,'html.parser')
            table = soup.find_all('td', attrs={'class': 'verif_col1'})

            premier = []
            for result in table:
                link = result.find('a', href=True)
                premier.append(link)
                truelink = 'https://www.verif.com/'+str(premier[0]).split('"')[1]
            #print("le lien", truelink)
        except Exception as e:
            print(e)
        finally:
            time.sleep(10)
    return truelink

Secondфункция для удаления ссылки.

def single_text(item_url):
    source_code = requests.get(item_url)
    print('nivo1 ok')
    plain_text = source_code.text # La page en html avec toutes ces balises
    soup = bs(plain_text,features="lxml" ) 
    print('nivo2 ok')
    table = soup.find('table',{'class':"table infoGen hidden-smallDevice"}) # on cherche que la balise table
    print('nivo1 ok', '\n', table)
    table_rows = table.find_all('tr') # les données de tables sont dans les celulles tr
    #print(table_rows)

    l = []
    for tr in table_rows:
        td = tr.find_all('td')
        row = row = [tr.text.strip() for tr in td] 
        l.append(row)
        # On enleve certains caractères unitiles
        df = pd.DataFrame(l)
    return df

Все эти функции работали, когда я проверял их по ссылке.

Теперь у меня есть CSV-файл с названием компаний, использующих searchsport () для поиска ввеб-сайт и возвращенная ссылка передается в single_text () для очистки.

for keyword in list(pd.read_csv('sport.csv').name):
    l = crawl(keyword)
    print(l) # THIS PRINT THE LINK
    single_item(l)    # HERE I GOT THE PROBLEME

Ошибка:


nivo1 ok
nivo2 ok
nivo1 ok 
 None

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-55-263d95d6748c> in <module>
      3     l = crawl(keyword)
      4 
----> 5     single_item(item_url=l)

<ipython-input-53-6d3b5c1b1ee8> in single_item(item_url)
      7     table = soup.find('table',{'class':"table infoGen hidden-smallDevice"}) # on cherche que la balise table
      8     print('nivo1 ok', '\n', table)
----> 9     table_rows = table.find_all('tr') # les données de tables sont dans les celulles tr
     10     #print(table_rows)
     11 

AttributeError: 'NoneType' object has no attribute 'find_all'

При запуске я получил df.

single_item(item_url="https://www.verif.com/societe/COMPANYNAME-XXXXXXXXX/").head(1)

Мои ожидаемые результаты должны быть два DataFrame для каждого ключевого слова. Почему это не работает?

Ответы [ 2 ]

1 голос
/ 18 октября 2019

Итак, я отметил во всем коде некоторые проблемы, которые я видел в вашем коде как опубликованные.

Некоторые вещи, которые я заметил:

Не обрабатывает случаи, когда что-то не найдено, например 'PARIS-SAINT-GERMAIN-FOOTBALL 'потерпит неудачу, в то время как' PARIS SAINT GERMAIN FOOTBALL 'в качестве поискового термина не упустит

Упущенные возможности для упрощения, например, создание кадра данных с помощью цикла tr, а затем td, когда можно просто использоватьread_html по table;Использование find_all, когда требуется один тег table или a

Перезапись переменных в циклах, а также опечатки, например

for tr in table_rows:
    td = tr.find_all('td')
    row = row = [tr.text.strip() for tr in td]  # presumable a typo with row = row

Не проверяется, является ли кадр данных пустым

Риск создания неверных URL с использованием 'https://www.verif.com/', так как следующая часть, к которой вы присоединяете, также начинается с "/"

Несогласованное именование переменных, например, что такое single_item? Функция, которую я вижу, называется single_text.

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

import requests, time
from bs4 import BeautifulSoup as bs
import pandas as pd


def searchsport(terme):
    url = f'https://www.verif.com/recherche/{terme}/1/ca/d/?ville=null'
    response = requests.get(url, headers = {'User-Agent':'Mozilla/5.0'})
    response.raise_for_status()
    return terme, response.text


def crawl(keyword):      
    try:
        keyword, html = searchsport(keyword)
        soup = bs(html,'lxml')
        a_tag = soup.select_one('td.verif_col1 a[href]') 
        # your code before when looping tds would just overwrite truelink if more than one found. Instead
        if a_tag is None:
             #handle case of no result e.g. with using crawl('PARIS-SAINT-GERMAIN-FOOTBALL') instead of
             #crawl('PARIS SAINT GERMAIN FOOTBALL')
            truelink = ''
        else:
            # print(a_tag['href'])
            # adding to the list premier served no purpose. Using split on href would result in list index out of range
            truelink = f'https://www.verif.com{a_tag["href"]}'  #relative link already so no extra / after .com

    except Exception as e:
        print(e)
        truelink = '' #handle case of 'other' fail. Make sure there is an assigment
    finally:
        time.sleep(5)
    return truelink #unless try succeeded this would have failed with local variable referenced before assignment


def single_text(item_url):
    source_code = requests.get(item_url, headers = {'User-Agent':'Mozilla/5.0'})
    print('nivo1 ok')
    plain_text = source_code.text # La page en html avec toutes ces balises
    soup = bs(plain_text,features="lxml") 
    print('nivo2 ok')
    table = soup.select_one('.table') # on cherche que la balise table
    #print('nivo1 ok', '\n', table)
    if table is None:
        df = pd.DataFrame()
    else:
        df = pd.read_html(str(table))[0] #simplify to work direct with table and pandas;avoid your loops
    return df

def main():

    terms = ['PARIS-SAINT-GERMAIN-FOOTBALL', 'PARIS SAINT GERMAIN FOOTBALL']

    for term in terms:
        item_url = crawl(term)
        if item_url:
            print(item_url)
            df = single_text(item_url)  # what is single_item in your question? There is single_text
            if not df.empty: #test if dataframe is empty
                print(df.head(1)) 

if __name__ == '__main__':
    main()

Возвращение df из main ()

import requests, time
from bs4 import BeautifulSoup as bs
import pandas as pd


def searchsport(terme):
    url = f'https://www.verif.com/recherche/{terme}/1/ca/d/?ville=null'
    response = requests.get(url, headers = {'User-Agent':'Mozilla/5.0'})
    response.raise_for_status()
    return terme, response.text


def crawl(keyword):      
    try:
        keyword, html = searchsport(keyword)
        soup = bs(html,'lxml')
        a_tag = soup.select_one('td.verif_col1 a[href]') 
        # your code before when looping tds would just overwrite truelink if more than one found. Instead
        if a_tag is None:
             #handle case of no result e.g. with using crawl('PARIS-SAINT-GERMAIN-FOOTBALL') instead of
             #crawl('PARIS SAINT GERMAIN FOOTBALL')
            truelink = ''
        else:
            # print(a_tag['href'])
            # adding to the list premier served no purpose. Using split on href would result in list index out of range
            truelink = f'https://www.verif.com{a_tag["href"]}'  #relative link already so no extra / after .com

    except Exception as e:
        print(e)
        truelink = '' #handle case of 'other' fail. Make sure there is an assigment
    finally:
        time.sleep(5)
    return truelink #unless try succeeded this would have failed with local variable referenced before assignment


def single_text(item_url):
    source_code = requests.get(item_url, headers = {'User-Agent':'Mozilla/5.0'})
    print('nivo1 ok')
    plain_text = source_code.text # La page en html avec toutes ces balises
    soup = bs(plain_text,features="lxml") 
    print('nivo2 ok')
    table = soup.select_one('.table') # on cherche que la balise table
    #print('nivo1 ok', '\n', table)
    if table is None:
        df = pd.DataFrame()
    else:
        df = pd.read_html(str(table))[0] #simplify to work direct with table and pandas;avoid your loops
    return df

def main():

    terms = ['PARIS-SAINT-GERMAIN-FOOTBALL', 'PARIS SAINT GERMAIN FOOTBALL']

    for term in terms:
        item_url = crawl(term)
        if item_url:
            #print(item_url)
            df = single_text(item_url)  # what is single_item in your question? There is single_text

    return df

if __name__ == '__main__':
    df = main()
    print(df)
1 голос
/ 18 октября 2019

Ваша ошибка говорит о том, что вы пытаетесь запустить find_all () для переменной, которая не была заполнена, т. Е. Не найден тег, для которого вы можете запустить find_all (). Я справился с этим, включив проверку операторов для NoneType

if VALUE is not None:
    ## code when the tag is found
else:
    ## code when tag is not found 

Я думаю, что это бит, который вам нужен для обновления, подобного этому,

  for tr in table_rows:
    if tr is not None:
        td = tr.find_all('td')
        row = row = [tr.text.strip() for tr in td] 
        l.append(row)
        # On enleve certains caractères unitiles
        df = pd.DataFrame(l)
    else:
        ## code to run when tr isn't populated

Есть более яркий пример, когда какой-то XML анализируется, где это в действии здесь

...