- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试从以下网站抓取航空公司的一些数据:http://www.airlinequality.com/airline-reviews/airasia-x[1] .
我设法获得了我需要的数据,但我在网页上的分页问题上苦苦挣扎。我正在尝试获取评论的所有标题(不仅是第一页中的标题)。
页面的链接格式为:http://www.airlinequality.com/airline-reviews/airasia-x/page/3/
其中3
是页码。
我尝试遍历这些 URL 以及以下代码片段,但抓取分页无效。
# follow pagination links
for href in response.css('#main > section.layout-section.layout-2.closer-top > div.col-content > div > article > ul li a'):
yield response.follow(href, self.parse)
如何解决?
import scrapy
import re # for text parsing
import logging
from scrapy.crawler import CrawlerProcess
class AirlineSpider(scrapy.Spider):
name = 'airlineSpider'
# page to scrape
start_urls = ['http://www.airlinequality.com/review-pages/a-z-airline-reviews/']
def parse(self, response):
# take each element in the list of the airlines
for airline in response.css("div.content ul.items li"):
# go inside the URL for each airline
airline_url = airline.css('a::attr(href)').extract_first()
# Call parse_airline
next_page = airline_url
if next_page is not None:
yield response.follow(next_page, callback=self.parse_article)
# follow pagination links
for href in response.css('#main > section.layout-section.layout-2.closer-top > div.col-content > div > article > ul li a'):
yield response.follow(href, self.parse)
# to go to the pages inside the links (for each airline) - the page where the reviews are
def parse_article(self, response):
yield {
'appears_ulr': response.url,
# use sub to replace \n\t \r from the result
'title': re.sub('\s+', ' ', (response.css('div.info [itemprop="name"]::text').extract_first()).strip(' \t \r \n').replace('\n', ' ') ).strip(),
'reviewTitle': response.css('div.body .text_header::text').extract(),
#'total': response.css('#main > section.layout-section.layout-2.closer-top > div.col-content > div > article > div.pagination-total::text').extract_first().split(" ")[4],
}
process = CrawlerProcess({
'USER_AGENT': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)',
'FEED_FORMAT': 'json',
'FEED_URI': 'air_test.json'
})
# minimizing the information presented on the scrapy log
logging.getLogger('scrapy').setLevel(logging.WARNING)
process.crawl(AirlineSpider)
process.start()
为了遍历航空公司,我使用以下代码解决了这个问题:它使用上面的代码:
req = Request("http://www.airlinequality.com/review-pages/a-z-airline-reviews/" , headers={'User-Agent': 'Mozilla/5.0'})
html_page = urlopen(req)
soupAirlines = BeautifulSoup(html_page, "lxml")
URL_LIST = []
for link in soupAirlines.findAll('a', attrs={'href': re.compile("^/airline-reviews/")}):
URL_LIST.append("http://www.airlinequality.com"+link.get('href'))
最佳答案
假设 scrapy 不是硬性要求,BeautifulSoup 中的以下代码将为您提供所有评论,解析出元数据,并最终输出 pandas DataFrame。从每条评论中提取的特定属性包括:
有一个处理分页的特定函数。它是一个递归函数,如果有下一页,我们再次调用该函数来解析新的 url,否则该函数调用结束。
from bs4 import BeautifulSoup
import requests
import pandas as pd
import re
# define global parameters
URL = 'http://www.airlinequality.com/airline-reviews/airasia-x'
BASE_URL = 'http://www.airlinequality.com'
MASTER_LIST = []
def parse_review(review):
"""
Parse important review meta data such as ratings, time of review, title,
etc.
Parameters
-------
review - beautifulsoup tag
Return
-------
outdf - pd.DataFrame
DataFrame representation of parsed review
"""
# get review header
header = review.find('h2').text
# get the numerical rating
base_review = review.find('div', {'itemprop': 'reviewRating'})
if base_review is None:
rating = None
rating_out_of = None
else:
rating = base_review.find('span', {'itemprop': 'ratingValue'}).text
rating_out_of = base_review.find('span', {'itemprop': 'bestRating'}).text
# get time of review
time_of_review = review.find('h3').find('time')['datetime']
# get whether review is verified
if review.find('em'):
verified = review.find('em').text
else:
verified = None
# get actual text of review
review_text = review.find('div', {'class': 'text_content'}).text
outdf = pd.DataFrame({'header': header,
'rating': rating,
'rating_out_of': rating_out_of,
'time_of_review': time_of_review,
'verified': verified,
'review_text': review_text}, index=[0])
return outdf
def return_next_page(soup):
"""
return next_url if pagination continues else return None
Parameters
-------
soup - BeautifulSoup object - required
Return
-------
next_url - str or None if no next page
"""
next_url = None
cur_page = soup.find('a', {'class': 'active'}, href=re.compile('airline-reviews/airasia'))
cur_href = cur_page['href']
# check if next page exists
search_next = cur_page.findNext('li').get('class')
if not search_next:
next_page_href = cur_page.findNext('li').find('a')['href']
next_url = BASE_URL + next_page_href
return next_url
def create_soup_reviews(url):
"""
iterate over each review, extract out content, and handle next page logic
through recursion
Parameters
-------
url - str - required
input url
"""
# use global MASTER_LIST to extend list of all reviews
global MASTER_LIST
soup = BeautifulSoup(requests.get(url).content, 'html.parser')
reviews = soup.findAll('article', {'itemprop': 'review'})
review_list = [parse_review(review) for review in reviews]
MASTER_LIST.extend(review_list)
next_url = return_next_page(soup)
if next_url is not None:
create_soup_reviews(next_url)
create_soup_reviews(URL)
finaldf = pd.concat(MASTER_LIST)
finaldf.shape # (339, 6)
finaldf.head(2)
# header rating rating_out_of review_text time_of_review verified
#"if approved I will get my money back" 1 10 ✅ Trip Verified | Kuala Lumpur to Melbourne. ... 2018-08-07 Trip Verified
# "a few minutes error" 3 10 ✅ Trip Verified | I've flied with AirAsia man... 2018-08-06 Trip Verified
如果我要做整个网站,我会使用上面的代码并遍历每家航空公司 here .我会修改代码以包含名为“航空公司”的列,以便您知道每条评论对应的航空公司。
关于python - 用 Python 抓取分页,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51922830/
我正在处理一组标记为 160 个组的 173k 点。我想通过合并最接近的(到 9 或 10 个组)来减少组/集群的数量。我搜索过 sklearn 或类似的库,但没有成功。 我猜它只是通过 knn 聚类
我有一个扁平数字列表,这些数字逻辑上以 3 为一组,其中每个三元组是 (number, __ignored, flag[0 or 1]),例如: [7,56,1, 8,0,0, 2,0,0, 6,1,
我正在使用 pipenv 来管理我的包。我想编写一个 python 脚本来调用另一个使用不同虚拟环境(VE)的 python 脚本。 如何运行使用 VE1 的 python 脚本 1 并调用另一个 p
假设我有一个文件 script.py 位于 path = "foo/bar/script.py"。我正在寻找一种在 Python 中通过函数 execute_script() 从我的主要 Python
这听起来像是谜语或笑话,但实际上我还没有找到这个问题的答案。 问题到底是什么? 我想运行 2 个脚本。在第一个脚本中,我调用另一个脚本,但我希望它们继续并行,而不是在两个单独的线程中。主要是我不希望第
我有一个带有 python 2.5.5 的软件。我想发送一个命令,该命令将在 python 2.7.5 中启动一个脚本,然后继续执行该脚本。 我试过用 #!python2.7.5 和http://re
我在 python 命令行(使用 python 2.7)中,并尝试运行 Python 脚本。我的操作系统是 Windows 7。我已将我的目录设置为包含我所有脚本的文件夹,使用: os.chdir("
剧透:部分解决(见最后)。 以下是使用 Python 嵌入的代码示例: #include int main(int argc, char** argv) { Py_SetPythonHome
假设我有以下列表,对应于及时的股票价格: prices = [1, 3, 7, 10, 9, 8, 5, 3, 6, 8, 12, 9, 6, 10, 13, 8, 4, 11] 我想确定以下总体上最
所以我试图在选择某个单选按钮时更改此框架的背景。 我的框架位于一个类中,并且单选按钮的功能位于该类之外。 (这样我就可以在所有其他框架上调用它们。) 问题是每当我选择单选按钮时都会出现以下错误: co
我正在尝试将字符串与 python 中的正则表达式进行比较,如下所示, #!/usr/bin/env python3 import re str1 = "Expecting property name
考虑以下原型(prototype) Boost.Python 模块,该模块从单独的 C++ 头文件中引入类“D”。 /* file: a/b.cpp */ BOOST_PYTHON_MODULE(c)
如何编写一个程序来“识别函数调用的行号?” python 检查模块提供了定位行号的选项,但是, def di(): return inspect.currentframe().f_back.f_l
我已经使用 macports 安装了 Python 2.7,并且由于我的 $PATH 变量,这就是我输入 $ python 时得到的变量。然而,virtualenv 默认使用 Python 2.6,除
我只想问如何加快 python 上的 re.search 速度。 我有一个很长的字符串行,长度为 176861(即带有一些符号的字母数字字符),我使用此函数测试了该行以进行研究: def getExe
list1= [u'%app%%General%%Council%', u'%people%', u'%people%%Regional%%Council%%Mandate%', u'%ppp%%Ge
这个问题在这里已经有了答案: Is it Pythonic to use list comprehensions for just side effects? (7 个答案) 关闭 4 个月前。 告
我想用 Python 将两个列表组合成一个列表,方法如下: a = [1,1,1,2,2,2,3,3,3,3] b= ["Sun", "is", "bright", "June","and" ,"Ju
我正在运行带有最新 Boost 发行版 (1.55.0) 的 Mac OS X 10.8.4 (Darwin 12.4.0)。我正在按照说明 here构建包含在我的发行版中的教程 Boost-Pyth
学习 Python,我正在尝试制作一个没有任何第 3 方库的网络抓取工具,这样过程对我来说并没有简化,而且我知道我在做什么。我浏览了一些在线资源,但所有这些都让我对某些事情感到困惑。 html 看起来
我是一名优秀的程序员,十分优秀!