#python #python-3.x #web-scraping #beautifulsoup
#python #python-3.x #очистка веб-страниц #beautifulsoup
Вопрос:
Я пишу свой первый скрипт, используя BS4 в качестве введения к веб-очистке, и у меня возникли проблемы. Я продолжаю автоматизировать скучные вещи с помощью руководства по Python, в котором он использует soup.select('insert class here')
для выбора классов. Когда я запускаю приведенный ниже код, он сообщает мне, что soup не является правильной командой AttributeError: 'Response' object has no attribute 'select'
import webbrowser
import selenium
import bs4
import requests
table = []
url = 'http://espn.com/mlb/team/stats/_/name/wsh'
r = requests.get(url)
page = bs4.BeautifulSoup(r.text)
table = soup.select("Table2__th")
print(str(table))
Комментарии:
1. должно быть
page.select()
неsoup.select()
, поскольку вы назвали свой объект Souppage
2. Хорошо, я это исправил. Теперь, когда я печатаю, он просто выдает мне пустой список.
Ответ №1:
Я предполагаю, что вам действительно нужны данные в таблице? Это содержимое отображается с использованием javascript, поэтому одни запросы не помогут, если вы нацелены на саму таблицу.
Еще лучше было бы использовать тег from script, тогда вы получите всю фактическую статистику. Ниже я беру эту информацию и помещаю в аккуратный фрейм данных для просмотра.
import bs4
import requests
import re
import json
import pandas as pd
url = 'http://espn.com/mlb/team/stats/_/name/wsh'
r = requests.get(url)
page = bs4.BeautifulSoup(r.text, 'lxml')
r = re.compile(r'playerStats":(.*),"teamLeaders"' , re.DOTALL)
data = page.find('script', text=r).text
script = r.findall(data)[0]
players_info = json.loads(script)
player_batting_stats = players_info[0]
expanded_player_batting_stats = players_info[1]
table1 = []
table2 = []
headers = ['Name', 'GP', 'AB', 'R', 'H', '2B', '3B', 'HR', 'RBI', 'TB', 'BB', 'K', 'SB', 'BA', 'OBP', 'SLG', 'OPS', 'WAR']
for player in player_batting_stats:
name = player['athlete']['name']
row = [stat['value'] for stat in player['statGroups']['stats']]
row.insert(0, name)
table1.append(row)
df1 = pd.DataFrame(table1, columns = headers)
print(df1.head())
# repeat for table2 using expanded_player_batting_stats
Комментарии:
1. Огромное спасибо! Знаете ли вы какие-либо хорошие ресурсы для изучения того, как работать с JS в Python при извлечении данных?
2. Я в восторге от этой техники, предназначенной для извлечения содержимого из тегов скрипта.
3. @SIM Это так удобно. К счастью, в python есть лучшая поддержка регулярных выражений, это точно.
4. джон — на самом деле вам не нужно много знать js (если есть) для этого конкретного подхода. Более полезно знать некоторые базовые регулярные выражения для определения шаблона и json для обработки объекта json (после синтаксического анализа из js с помощью библиотеки json). В более общем плане, знание некоторых js очень удобно для написания собственной функциональности при работе с веб-сайтами и необходимости чего-либо, недоступного в библиотеках python. Мне приходилось делать это на других языках, но пока не на python, поскольку для python доступно так много функциональных возможностей.
Ответ №2:
Здесь две проблемы:
- вы определили свой объект soup как
page
, но затем пытаетесь ссылаться на него какsoup
. Вы должны делатьpage.select('...')
- вы пытаетесь выбрать определенный класс в CSS, поэтому ваш выбор должен быть
".Table2__th"
(в CSS имени класса предшествует точка). Смотрите https://facelessuser.github.io/soupsieve / для получения дополнительной информации о селекторах CSS.
Вот рабочая версия вашего кода:
import bs4
import requests
table = []
url = 'http://espn.com/mlb/team/stats/_/name/wsh'
r = requests.get(url)
page = bs4.BeautifulSoup(r.text)
table = page.select(".Table2__th")
print(str(table))