在众多领域中,无论是语音识别还是理解客户对产品的情感倾向等,智能和机器学习都有着广泛的应用。然而,要构建一个可靠且健壮的模型,需要大量的数据。网络爬虫是收集这些海量数据的一种方式。
互联网拥有庞大的数据量,可以使用这些数据来训练模型。网络爬虫(或网络爬行)是一种收集这些信息的方法。此外,这些信息可能是非结构化或半结构化的。网络爬虫还可以帮助将这些信息结构化。在Python中,BeautifulSoup、Scrapy和Selenium是用于网络爬虫的最常用库。
在本文中,将抓取IMDB网站上所有关于《哈利·波特与魔法石》的评论。可以使用这些评论数据执行多种自然语言处理任务(例如情感分析或角色/演员流行度趋势分析等)。
Selenium是一个非常流行的库,通常用于自动化测试。Scrapy是一个非常流行且广泛使用的网络爬虫库。将使用Selenium库加载评论,使用Scrapy库提取相关信息。
pip install selenium
pip install scrapy
如前所述,Selenium是一个测试工具。在本文中,将使用Chrome浏览器进行探索。为此,需要从以下位置下载相应的chromedriver:
需要将chromedriver.exe存储在运行代码的文件夹中。
让导入所有相关库。
import numpy as np
import pandas as pd
from scrapy.selector import Selector
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time
from tqdm import tqdm
import warnings
warnings.filterwarnings("ignore")
在这里,将传递哈利波特评论的URL,并使用selenium打开浏览器并访问该URL。此外,将通过调用页面下按钮三次来滚动页面。
driver = webdriver.Chrome('chromedriver.exe')
url = 'https://www.imdb.com/title/tt0241527/reviews?ref_=tt_sa_3'
time.sleep(1)
driver.get(url)
time.sleep(1)
print(driver.title)
time.sleep(1)
body = driver.find_element(By.CSS_SELECTOR, 'body')
body.send_keys(Keys.PAGE_DOWN)
time.sleep(1)
body.send_keys(Keys.PAGE_DOWN)
time.sleep(1)
body.send_keys(Keys.PAGE_DOWN)
要从HTML中提取任何信息,需要了解如何解析HTML页面。因此,将右键单击网页并单击检查元素。应该看到类似下面的内容。
在右侧看到的是网站的HTML代码。如果查看右侧的Html代码,评论数量似乎出现在(具有lister类的div)->(具有header类的div)->span中。将使用scrapy选择器提取此信息。
在Scrapy中,如果想通过类提取,使用点后跟类名。同样,如果想通过id提取,使用井号后跟id名称。查看代码将使这变得容易理解。可以参考Scrapy文档以获取详细信息。让将页面的HTML代码传递给Scrapy选择器并提取总评论数量。
sel = Selector(text = driver.page_source)
review_counts = sel.css('.lister .header span::text').extract_first().replace(',','').split(' ')[0]
more_review_pages = int(int(review_counts)/25)
看起来页面有超过1900条评论,但每页只能看到25条。因此,需要点击页面末尾的加载更多按钮。使用检查元素,可以看到加载所有评论是一个具有id的按钮。
让使用selenium来调用点击该按钮以加载所有评论。由于每页包含25条评论,需要点击大约77次加载更多按钮。将使用在步骤4中计算的more_review_pages变量。
for i in tqdm(range(more_review_pages))
try:
css_selector = 'load-more-trigger'
driver.find_element(By.ID, css_selector).click()
except:
pass
经过检查,可以看到每条评论都存储在具有review-container类的div中。在该分区内,可以使用检查元素找到标签位置。让以第一条评论为例。现在,评分存储在具有rating-other-user-rating类的span标签中。
要提取此信息,需要使用Scrapy库。将第一条评论的HTML代码传递给Scrapy选择器并提取评分值。
reviews = driver.find_elements(By.CSS_SELECTOR, 'div.review-container')
first_review = reviews[0]
sel2 = Selector(text = first_review.get_attribute('innerHTML'))
rating = sel2.css('.rating-other-user-rating span::text').extract_first().strip()
类似地,可以使用以下代码找到该评论的其他指标。
review = sel2.css('.text.show-more__control::text').extract_first().strip()
review_date = sel2.css('.review-date::text').extract_first().strip()
author = sel2.css('.display-name-link a::text').extract_first().strip()
review_title = sel2.css('a.title::text').extract_first().strip()
review_url = sel2.css('a.title::attr(href)').extract_first().strip()
helpfulness = sel2.css('.actions.text-muted::text').extract_first().strip()
print('Rating:',rating)
print('Review Title:',review_title)
print('Author:',author)
print('Review Date:',review_date)
print('Review:',review)
print('Helpfulness:',helpfulness)
现在,可以编写一个for循环来提取所有评论的所有信息。
rating_list = []
review_date_list = []
review_title_list = []
author_list = []
review_list = []
review_url_list = []
error_url_list = []
error_msg_list = []
reviews = driver.find_elements(By.CSS_SELECTOR, 'div.review-container')
对于每条评论,尝试提取评分、评论内容、评论日期、、评论标题和评论URL。如果提取失败,将错误信息和URL添加到错误列表中。
for d in tqdm(reviews):
try:
sel2 = Selector(text = d.get_attribute('innerHTML'))
try:
rating = sel2.css('.rating-other-user-rating span::text').extract_first()
except:
rating = np.NaN
try:
review = sel2.css('.text.show-more__control::text').extract_first()
except:
review = np.NaN
try:
review_date = sel2.css('.review-date::text').extract_first()
except:
review_date = np.NaN
try:
author = sel2.css('.display-name-link a::text').extract_first()
except:
author = np.NaN
try:
review_title = sel2.css('a.title::text').extract_first()
except:
review_title = np.NaN
try:
review_url = sel2.css('a.title::attr(href)').extract_first()
except:
review_url = np.NaN
rating_list.append(rating)
review_date_list.append(review_date)
review_title_list.append(review_title)
author_list.append(author)
review_list.append(review)
review_url_list.append(review_url)
except Exception as e:
error_url_list.append(url)
error_msg_list.append(e)
review_df = pd.DataFrame({'Review_Date':review_date_list, 'Author':author_list, 'Rating':rating_list, 'Review_Title':review_title_list, 'Review':review_list, 'Review_Url':review_url})
成功地抓取了IMDB上特定电影的所有评论。