Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/90.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Steam crawler/scraper Python脚本未生成所需的所有信息?_Python_Html_Web Scraping_Web Crawler_Steam - Fatal编程技术网

Steam crawler/scraper Python脚本未生成所需的所有信息?

Steam crawler/scraper Python脚本未生成所需的所有信息?,python,html,web-scraping,web-crawler,steam,Python,Html,Web Scraping,Web Crawler,Steam,我目前正在使用一个Steam crawler()脚本,该脚本基于带有游戏ID的数据集,能够抓取Steam评论数据(日期、评论文本、用户ID等)。我不是HTML抓取方面的专家,但根据我从代码(如下所示)中了解到的情况,脚本正在循环给定的游戏ID以收集所有评论,直到遇到这种特定情况endre=re.compile(r'({“success”:2})|(无更多评论) import argparse 导入csv 导入操作系统 进口稀土 导入套接字 导入字符串 导入URL库 导入urllib.reques

我目前正在使用一个Steam crawler()脚本,该脚本基于带有游戏ID的数据集,能够抓取Steam评论数据(日期、评论文本、用户ID等)。我不是HTML抓取方面的专家,但根据我从代码(如下所示)中了解到的情况,脚本正在循环给定的游戏ID以收集所有评论,直到遇到这种特定情况
endre=re.compile(r'({“success”:2})|(无更多评论)

import argparse
导入csv
导入操作系统
进口稀土
导入套接字
导入字符串
导入URL库
导入urllib.request
导入urllib.parse
导入json
从上下文库导入关闭
从时间上导入睡眠
def下载页面(url、maxretries、超时、暂停):
尝试=0
htmlpage=None
而Trys=maxError:
打印('最大错误!')
打破
其他:
将open(os.path.join(gamedir,'reviews-%s.html'%page','w',encoding='utf-8')作为f:
htmlpage=htmlpage.decode()
如果endre.search(htmlpage):
打破
f、 写入(htmlpage)
第页=第+1页
解析的_json=(json.loads(htmlpage))
cursor=urllib.parse.quote(已解析的_json['cursor'])
将open(donefilename,'w',encoding='utf-8')作为f:
通过
def main():
parser=argparse.ArgumentParser(description='Strawler of Steam reviews')
parser.add_参数('-f','-force',help='force download,即使已成功下载,'必需=False,
action='store\u true')
parser.add_参数(
'-t','-timeout',help='http连接的超时时间(秒)。默认值:180',
必需=False,类型=int,默认值=180)
parser.add_参数(
'-r','-maxretries',help='Max retries下载文件。默认值:5',
必需=False,类型=int,默认值=3)
parser.add_参数(
'-p','-pause',help='http请求之间等待的秒数。默认值:0.5',required=False,默认值=0.01,
类型=浮动)
parser.add_参数(
'-m','-maxreviews',help='每个项目可下载的最大评论数。默认值:unlimited',required=False,
类型=整数,默认值=5000000)
parser.add_参数(
'-o'、'-out',help='Output base path',required=False,default='data')
parser.add_参数(
'-i'、'-id',help='File with game id',required=False,default='./data/games.csv')
args=parser.parse_args()
如果操作系统路径不存在(args.out):
os.makedirs(args.out)
ids=GetGameID(args.ids)
打印(“%s”游戏“%len(id))
getgamereviews(ID、args.timeout、args.maxretries、args.pause、args.out)
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
main()
我目前面临的问题是,脚本没有正确地提取评论:例如,对于像《反恐全球攻势》这样拥有约1000000条评论的游戏,脚本有时会返回4000页评论(每个html页面包含20条评论)、6000页或500页,直到停止

我设想的解决方案可能是保存脚本测试的每个URL,并在每次
endre=re.compile(r'({“success”:2})|(no_more_reviews)
为真时重复循环10次,并跳过已收集的URL,但我不确定它是否真的有效

我也会在GitHub页面上提出这个问题,但作者似乎并不经常回应,我真的很想知道为什么会发生这种情况,以及是否有可能解决这个问题。先谢谢你

编辑:所以我看了一下Steam API文档,似乎每一页都有一个光标,可以加载下一页。那么为什么它会随机变化呢?

就像是web服务器的一种基本自卫形式。Steam使用它来帮助防止其服务器被滥用(太多)
import argparse
import csv
import os
import re
import socket
import string
import urllib
import urllib.request
import urllib.parse
import json
from contextlib import closing
from time import sleep


def download_page(url, maxretries, timeout, pause):
    tries = 0
    htmlpage = None
    while tries < maxretries and htmlpage is None:
        try:
            with closing(urllib.request.urlopen(url, timeout=timeout)) as f:
                htmlpage = f.read()
                sleep(pause)
        except (urllib.error.URLError, socket.timeout, socket.error):
            tries += 1
    return htmlpage


def getgameids(filename):
    ids = set()
    with open(filename, encoding='utf8') as f:
        reader = csv.reader(f)
        for row in reader:
            dir = row[0] #à la base c'est 0
            id_ = row[1]
            name = row[2]
            ids.add((dir, id_, name))
    return ids


def getgamereviews(ids, timeout, maxretries, pause, out):
    urltemplate = string.Template(
        'https://store.steampowered.com//appreviews/$id?cursor=$cursor&filter=recent&language=english')
    endre = re.compile(r'({"success":2})|(no_more_reviews)')

    for (dir, id_, name) in ids:
        if dir == 'sub':
            print('skipping sub %s %s' % (id_, name))
            continue

        gamedir = os.path.join(out, 'pages', 'reviews', '-'.join((dir, id_)))

        donefilename = os.path.join(gamedir, 'reviews-done.txt') #When all reviews of a given have been extracted
        if not os.path.exists(gamedir):  #Create a folder if not existing
            os.makedirs(gamedir)
        elif os.path.exists(donefilename): #if folder exists, skip game
            print('skipping app %s %s' % (id_, name))
            continue

        print(dir, id_, name)

        cursor = '*'
        offset = 0
        page = 1
        maxError = 10
        errorCount = 0
        i = 0
        while True:
            url = urltemplate.substitute({'id': id_, 'cursor': cursor})
            print(offset, url)
            htmlpage = download_page(url, maxretries, timeout, pause)

            if htmlpage is None:
                print('Error downloading the URL: ' + url)
                sleep(pause * 3)
                errorCount += 1
                if errorCount >= maxError:
                    print('Max error!')
                    break
            else:
                with open(os.path.join(gamedir, 'reviews-%s.html' % page), 'w', encoding='utf-8') as f:
                    htmlpage = htmlpage.decode()
                    if endre.search(htmlpage):
                        break
                    f.write(htmlpage)
                    page = page + 1
                    parsed_json = (json.loads(htmlpage))
                    cursor = urllib.parse.quote(parsed_json['cursor'])

        with open(donefilename, 'w', encoding='utf-8') as f:
            pass


def main():
    parser = argparse.ArgumentParser(description='Crawler of Steam reviews')
    parser.add_argument('-f', '--force', help='Force download even if already successfully downloaded', required=False,
                        action='store_true')
    parser.add_argument(
        '-t', '--timeout', help='Timeout in seconds for http connections. Default: 180',
        required=False, type=int, default=180)
    parser.add_argument(
        '-r', '--maxretries', help='Max retries to download a file. Default: 5',
        required=False, type=int, default=3)
    parser.add_argument(
        '-p', '--pause', help='Seconds to wait between http requests. Default: 0.5', required=False, default=0.01,
        type=float)
    parser.add_argument(
        '-m', '--maxreviews', help='Maximum number of reviews per item to download. Default:unlimited', required=False,
        type=int, default=5000000)
    parser.add_argument(
        '-o', '--out', help='Output base path', required=False, default='data')
    parser.add_argument(
        '-i', '--ids', help='File with game ids', required=False, default='./data/games.csv')
    args = parser.parse_args()

    if not os.path.exists(args.out):
        os.makedirs(args.out)

    ids = getgameids(args.ids)

    print('%s games' % len(ids))

    getgamereviews(ids, args.timeout, args.maxretries, args.pause, args.out)


if __name__ == '__main__':
    main()