Как мне извлечь имя пользователя, сообщение и дату публикации с доски обсуждений? - PullRequest
1 голос
/ 21 июня 2020

Как мне продолжить работу с этим проектом по очистке веб-страниц, используя bs4 и запросы? Я пытаюсь извлечь информацию о пользователе с сайта форума (в точности myfitnesspal: https://community.myfitnesspal.com/en/discussion/10703170/what-were-eating/p1), в частности имя пользователя, сообщение и дату публикации, и загрузить их в столбцы в CSV. У меня пока есть этот код, но я не уверен, что делать дальше:

from bs4 import BeautifulSoup
import csv
import requests

# get page source and create a BS object
print('Reading page...')

page= requests.get('https://community.myfitnesspal.com/en/discussion/10703170/what-were-eating/p1')
src = page.content

soup = BeautifulSoup(src, 'html.parser')

#container = soup.select('#vanilla_discussion_index > div.container')

container = soup.select('#vanilla_discussion_index > div.container > div.row > div.content.column > div.CommentsWrap > div.DataBox.DataBox-Comments > ul')

postdata = soup.select('div.Message')

user = []
date = []
text = []

for post in postdata:
    text.append(BeautifulSoup(str(post), 'html.parser').get_text().encode('utf-8').strip())

print(text) # this stores the text of each comment/post in a list,
            # so next I'd want to store this in a csv with columns 
            # user, date posted, post with this under the post column
            # and do the same for user and date

Ответы [ 3 ]

2 голосов
/ 21 июня 2020

Одно практическое правило, которое я придерживаюсь при парсинге веб-страниц, - это указывать c как можно более без сбора ненужной информации. Так, например, если я хочу выбрать имя пользователя, я проверяю элемент, содержащий нужную мне информацию:

<a class="Username" href="...">Username</a>

Поскольку я пытаюсь собрать имена пользователей, имеет смысл выбирать по классу «Имя пользователя» :

soup.select("a.Username")

Это дает мне список всех имен пользователей, которые можно найти на странице, это замечательно, однако, если мы хотим выбрать данные в «пакетах» (по почте в вашем примере мы нужно собирать каждое сообщение индивидуально.

Для выполнения sh этого вы можете сделать что-то вроде следующего:

comments = soup.select("div.comment")

Это упростит выполнение следующих действий:

with open('file.csv', 'w', newline='') as file:
    writer = csv.writer(file)
    writer.writerow(['user', 'date', 'text']
    for comment in comments:
        username = comment.select_one("div.Username")
        date = comment.select_one("span.BodyDate")
        message = comment.select_one("div.Message")
        writer.writerow([username, date, message])

Выполнение этого способа также гарантирует, что ваши данные останутся в порядке, даже если элемент отсутствует.

2 голосов
/ 21 июня 2020

Этот скрипт получит все сообщения со страницы и сохранит их в data.csv:

import csv
import requests
from bs4 import BeautifulSoup


url = 'https://community.myfitnesspal.com/en/discussion/10703170/what-were-eating/p1'

soup = BeautifulSoup(requests.get(url).content, 'html.parser')

all_data = []
for u, d, m in zip(soup.select('.Username'), soup.select('.DateCreated'), soup.select('.Message')):
    all_data.append([u.text, d.get_text(strip=True),m.get_text(strip=True, separator='\n')])

with open('data.csv', 'w', newline='') as csvfile:
    writer = csv.writer(csvfile, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
    for row in all_data:
        writer.writerow(row)

Скриншот из LibreOffice:

введите описание изображения здесь

1 голос
/ 21 июня 2020

Вот go:

from bs4 import BeautifulSoup
import csv
import requests


page= requests.get('https://community.myfitnesspal.com/en/discussion/10703170/what-were-eating/p1')
soup = BeautifulSoup(page.content, 'html.parser')
container = soup.select('#vanilla_discussion_index > div.container > div.row > div.content.column > div.CommentsWrap > div.DataBox.DataBox-Comments > ul > li')

with open('data.csv', 'w') as f:
    writer = csv.DictWriter(f, fieldnames=['user', 'date', 'text'])
    writer.writeheader()
    for comment in container:
        writer.writerow({
            'user': comment.find('a', {'class': 'Username'}).get_text(),
            'date': comment.find('span', {'class': 'BodyDate DateCreated'}).get_text().strip(),
            'text': comment.find('div', {'class': 'Message'}).get_text().strip()
        })
...