在启用cookie的网站上使用urlretrieve的多线程Web刮板

如何解决在启用cookie的网站上使用urlretrieve的多线程Web刮板

|| 我正在尝试编写我的第一个Python脚本,并且通过大量的Google搜索,我认为我快完成了。但是,我将需要一些帮助以使自己跨过终点线。 我需要编写一个脚本,该脚本登录到启用Cookie的网站,抓取一堆链接,然后生成一些进程来下载文件。我的程序在单线程中运行,所以我知道代码可以工作。但是,当我尝试创建一批下载工作者时,我遇到了障碍。
#manager.py
import Fetch # the module name where worker lives
from multiprocessing import pool

def FetchReports(links,Username,Password,VendorID):
    pool = multiprocessing.Pool(processes=4,initializer=Fetch._ProcessStart,initargs=(SiteBase,DataPath,VendorID,))
    pool.map(Fetch.DownloadJob,links)
    pool.close()
    pool.join()


#worker.py
import mechanize
import atexit

def _ProcessStart(_SiteBase,_DataPath,User,VendorID):
    Login(User,Password)

    global SiteBase
    SiteBase = _SiteBase

    global DataPath
    DataPath = _DataPath

    atexit.register(Logout)

def DownloadJob(link):
    mechanize.urlretrieve(mechanize.urljoin(SiteBase,link),filename=DataPath+\'\\\\\'+filename,data=data)
    return True
在此修订版中,代码失败,因为尚未将Cookie传输到工作程序供urlretrieve使用。没问题,我能够使用机械化的.cookiejar类将cookie保存在管理器中,并将它们传递给工作人员。
#worker.py
import mechanize
import atexit

from multiprocessing import current_process

def _ProcessStart(_SiteBase,VendorID):
    global cookies
    cookies = mechanize.LWPCookieJar()

    opener = mechanize.build_opener(mechanize.HTTPCookieProcessor(cookies))

    Login(User,opener)  # note I pass the opener to Login so it can catch the cookies.

    global SiteBase
    SiteBase = _SiteBase

    global DataPath
    DataPath = _DataPath

    cookies.save(DataPath+\'\\\\\'+current_process().name+\'cookies.txt\',True,True)

    atexit.register(Logout)

def DownloadJob(link):
    cj = mechanize.LWPCookieJar()
    cj.revert(filename=DataPath+\'\\\\\'+current_process().name+\'cookies.txt\',ignore_discard=True,ignore_expires=True)
    opener = mechanize.build_opener(mechanize.HTTPCookieProcessor(cj))

    file = open(DataPath+\'\\\\\'+filename,\"wb\")
    file.write(opener.open(mechanize.urljoin(SiteBase,link)).read())
    file.close
但是,那失败了,因为打开程序(我认为)想将二进制文件移回管理器进行处理,并且出现“无法腌制对象”错误消息,指的是它试图读取的网页文件。 显而易见的解决方案是从cookie罐中读取cookie,并在发出urlretrieve请求时手动将其添加到标头中,但是我试图避免这种情况,这就是为什么我要寻求建议的原因。     

解决方法

正确的方法来创建多线程的Web抓取工具很困难。我确定您可以处理,但是为什么不使用已经完成的操作呢? 我真的很建议您查看Scrapy http://scrapy.org/ 这是一个非常灵活的开源Web爬虫框架,可以处理您在此处需要的大多数内容。使用Scrapy,运行并发蜘蛛是一个配置问题,而不是编程问题(http://doc.scrapy.org/topics/settings.html#concurrent-requests-per-spider)。您还将获得对Cookie,代理,HTTP身份验证等的支持。 对我来说,用Scrapy重写了我的刮板花了大约4个小时。因此,请问自己:您是否真的想自己解决线程问题,还是爬到其他人的肩膀上并专注于Web抓取而不是线程问题? PS。您现在正在使用机械化吗?请从机械化常见问题解答http://wwwsearch.sourceforge.net/mechanize/faq.html中注意到这一点: \“它是线程安全的吗? 不。据我所知,您可以在线程代码中使用机械化,但是它不提供同步:您必须自己提供。” 如果您真的想继续使用机械化,请开始阅读有关如何提供同步的文档。 (例如,http://effbot.org/zone/thread-synchronization.htm、http://effbot.org/pyfaq/what-kinds-of-global-value-mutation-are-thread-safe.htm)     ,经过一天的大部分工作后,事实证明机械化不是问题,它看起来更像是编码错误。经过大量的调整和诅咒,我得到了可以正常工作的代码。 对于像我这样的未来Google员工,我在下面提供了更新的代码:
#manager.py [unchanged from original]
def FetchReports(links,Username,Password,VendorID):
    import Fetch
    import multiprocessing

    pool = multiprocessing.Pool(processes=4,initializer=Fetch._ProcessStart,initargs=(SiteBase,DataPath,VendorID,))
    pool.map(Fetch.DownloadJob,_SplitLinksArray(links))
    pool.close()
    pool.join()


#worker.py
import mechanize
from multiprocessing import current_process

def _ProcessStart(_SiteBase,_DataPath,User,VendorID):
    global cookies
    cookies = mechanize.LWPCookieJar()
    opener = mechanize.build_opener(mechanize.HTTPCookieProcessor(cookies))

    Login(User,opener)

    global SiteBase
    SiteBase = _SiteBase

    global DataPath
    DataPath = _DataPath

    cookies.save(DataPath+\'\\\\\'+current_process().name+\'cookies.txt\',True,True)

def DownloadJob(link):
    cj = mechanize.LWPCookieJar()
    cj.revert(filename=DataPath+\'\\\\\'+current_process().name+\'cookies.txt\',True)
    opener = mechanize.build_opener(mechanize.HTTPCookieProcessor(cj))

    mechanize.urlretrieve(url=mechanize.urljoin(SiteBase,link),filename=DataPath+\'\\\\\'+filename,data=data)
因为我只是从列表中下载链接,所以机械化的非线程安全性质似乎不是问题[完全公开:我已经运行了3次此过程,因此在进一步测试中可能会出现问题]。多处理模块及其工作人员池承担了所有繁重的工作。维护文件中的cookie对我来说很重要,因为我从中下载的Web服务器必须为每个线程提供其自己的会话ID,但是实现此代码的其他人可能不需要使用它。我确实注意到,它似乎在初始化调用和运行调用之间“忘记了”变量,因此cookiejar可能不会跳转。     ,为了在第一个代码示例中启用cookie会话,请将以下代码添加到功能DownloadJob中:
cj = mechanize.LWPCookieJar()
opener = mechanize.build_opener(mechanize.HTTPCookieProcessor(cj))
mechanize.install_opener(opener)
然后,您可以按照以下方式检索网址:
mechanize.urlretrieve(mechanize.urljoin(SiteBase,data=data)
    

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 <select id="xxx"> SELECT di.id, di.name, di.work_type, di.updated... <where> <if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 <property name="dynamic.classpath" value="tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-