快上车,scrapy爬虫飙车找福利(二)

上一篇文章实现的最简单的爬虫,抓取了某个链接下第一次加载的所有图片链接。因为存在下拉刷新, 因此怎么获得该页面的全部答案是这篇文章需要去处理的事情。

方案:

  1. 抓包,看下拉刷新向服务器发送什么请求,模拟去发送请求(结构化数据适用)
  2. selenium执行js的滑动到底部,判断是否滑动到底部,以此循环。

具体实施;

这里选择使用方案2,方案1后面遇到再讨论。

一:selenium的简单使用。
这里涉及selenium的安装,Selenium with Python官方文档讲解的特别简单。我使用的的chrome(可以配置无头属性)。
注意:需要将下载的driver配置环境变量,以便可以访问。

if __name__ == '__main__':
    options = webdriver.ChromeOptions()
    options.add_argument('headless')
    # driver = webdriver.Chrome(options=options)
    driver = webdriver.Chrome()
    driver.implicitly_wait(2)
    driver.get("https://www.zhihu.com/question/22856657")
    time.sleep(2)
    resSoup = BeautifulSoup(driver.page_source, 'lxml')
    items = resSoup.select("figure > span > div")
    print(len(items))
    for item in items:
        print(item)
    #driver.close()

在项目执行代码可以看到输出:python zhihu/spiders/zhihu.py

image.png

可以看到共抓到198张图片,对去data-src属性即可得图片链接。
代码解释:
前三行用于启动一个无头的driver。如果需要查看加载的情况,只用第四行代码即可,执行完毕可以查看浏览器打开的url, 如下。
image.png

接下来三行:
第一行启动driver的隐式等待,简单意思就是:2秒内网页加载完毕就往下执行,否则就加载完2秒,继续往下执行。
第二行用于打开链接,相当于手动在地址栏输入链接。
第三行延时,等待网页加载。
后面的内容前面有接触。
如果输出结果和我的相差不大,那么继续下一步。

二:selenium执行js代码,加载全部内容。

if __name__ == '__main__':
    options = webdriver.ChromeOptions()
    options.add_argument('headless')
    # driver = webdriver.Chrome(options=options)
    driver = webdriver.Chrome()
    driver.implicitly_wait(2)
    driver.get("https://www.zhihu.com/question/22856657")
    time.sleep(2)

    count = 1
    css_selector = "#root > div > main > div > div.Question-main > div.Question-mainColumn > div > div.Card > button"
    css_selector2 = "#root > div > main > div > div.Question-main > div.Question-mainColumn > div > div.CollapsedAnswers-bar"
    while len(driver.find_elements_by_css_selector(css_selector)) == 0 and \
            len(driver.find_elements_by_css_selector(css_selector2)) == 0:
        print("count:" + str(count))
        js = "var q=document.documentElement.scrollTop=" + str(count * 200000)
        count += 1
        driver.execute_script(js)
        time.sleep(0.5)

    resSoup = BeautifulSoup(driver.page_source, 'lxml')
    items = resSoup.select("figure > span > div")
    print(len(items))
    for item in items:
        print(item)
image.png

结果输出:共计抓取翻页13次,抓取662个图片链接。
中间部分新增的代码, count用于记录翻页次数。
css_selector和css_selector2用于判断某个元素是否存在,决定是否滑动到底部,如下。


image.png

用一个循环去执行js代码,简单意思是滑动到距离页面顶部x的距离。经过测试,200000/页是比较好的选择。

至此,可以抓取某个链接下的所有图片。

三: selenium与spider middlewares的结合。
上面一切顺利之后, 接下来去使双方结合。
关于scrapy 的下载中间键(DOWNLOADER_MIDDLEWARES):
简单来说,该中间键就是调用process_request, 将获取url的request经过处理,返回request,response,None三值之一。
返回 request:继续执行后面的process_request方法(包括中间键)
response:不知行后面的process_request方法,以此response结果直接返回,执行zhihu/spiders/zhihu.py 的回调方法。
具体请看官方文档: https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
(还有spider middlewares, 本次未用到)

image.png

话不多说,开始写代码:
在middlewares.py中定义自己的中间键:


class PhantomJSMiddleware(object):

    def __init__(self):
        options = webdriver.ChromeOptions()
        options.add_argument('headless')
        self.driver = webdriver.Chrome()
        self.driver.implicitly_wait(1)

    def process_request(self, request, spider):
        print(request.url)
        driver = self.nextPage(request)
        return HtmlResponse(url=request.url, body=driver.page_source, encoding="utf-8")
        # 翻页操作

    def nextPage(self, request):
        self.driver.get(request.url)
        time.sleep(2)
        count = 1
        css_selector = "#root > div > main > div > div.Question-main > div.Question-mainColumn > div > div.Card > button"
        css_selector2 = "#root > div > main > div > div.Question-main > div.Question-mainColumn > div > div.CollapsedAnswers-bar"
        # css_selector = "div > a > img"
        # print(len(self.driver.find_elements_by_css_selector(css_selector)))
        while len(self.driver.find_elements_by_css_selector(css_selector)) == 0 and len(
                self.driver.find_elements_by_css_selector(css_selector2)) == 0:
            print("count:" + str(count))
            js = "var q=document.documentElement.scrollTop=" + str(count * 200000)
            count += 1
            self.driver.execute_script(js)
            time.sleep(0.5)
        print(count)
        time.sleep(2)
        return self.driver

    @classmethod
    # 信号的使用
    def from_crawler(cls, crawler):
        print("from_crawler")
        # This method is used by Scrapy to create your spiders.
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_closed)
        return s

    def spider_opened(self, spider):
        print("spider close")
        self.driver.close()

稍作解释:
__init__函数做初始化工作,
nextPage函数根据得到的request做翻页操作。
process_request函数是中间键的必要函数, 启动中间键之后,yield生成器中的request都会经过该函数,然后返回结果(一定要在此函数执行return)。

后面是spiders信号的使用实例, 用于在spiders执行结束的时候做处理工作,比如关闭driver等操作。

setttings.py:配置对下载中间键的使用。

DOWNLOADER_MIDDLEWARES = {
    'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,
    'zhihu.middlewares.PhantomJSMiddleware': 100,
}

以上配置完毕,即可执行爬虫。
命令行执行 scrapy crawl zhihu启动爬虫,注意看日志,有如下输出。

image.png

下拉刷新根据网速决定,所以count值会有不同。
可以看到这里抓取到了660张图片链接(允许个别误差)。

至此,对于使用scrapy结合selnium抓取动态网页已经不是问题。

对于某些需要登录的链接,打开url之后会直接去到登录页。下一篇文章介绍怎么使用selenium 去登录,保存cookies, 带着cookies去请求(可能是万能的登录方法,对于图片验证, 手机验证码也可能适用)。

微信:youquwen1226
github:https://github.com/yunshuipiao
欢迎来信一起探讨。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,277评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,777评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,946评论 0 245
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,271评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,636评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,767评论 1 221
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,989评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,733评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,457评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,674评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,155评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,518评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,160评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,114评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,898评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,822评论 2 280
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,705评论 2 273

推荐阅读更多精彩内容