python爬虫——使用selenium爬取知网文献相关信息


写在前面:

本文章限于交流讨论,请不要使用文章的代码去攻击别人的服务器
    如侵权联系作者删除
    文中的错误已经修改过来了,谢谢各位爬友指出错误
    在你复制本文章代码去运行的时候,请设置延迟,给自己留一条后路
    转载请注明来源,谢谢

谷歌驱动器下载网站

1. 先看爬取的效果


2.

知网的反爬虫手段很强,反正我爬取pc端的时候,用selenium爬取获取不到源代码,真是气人,后来换成手机端就可以获取了,爬取手机端的操作如下。

3. 首先进入知网后,选择开发工具,建议放在右边,之后再点击图中红框的东东,然后刷新一下网页就切换到手机端了

4.进入手机端的界面如下图所示(注:记得刷新网页):

5. 这是网址

6. 首先在调用selenium之前设置一些参数

from selenium import webdriver
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.common.by import By
    import time
    import json
    import csv

    # 设置谷歌驱动器的环境
    options = webdriver.ChromeOptions()
    # 设置chrome不加载图片提高速度
    options.add_experimental_option("prefs", {"profile.managed_default_content_settings.images": 2})
    # 创建一个谷歌驱动器
    browser = webdriver.Chrome(options=options)
    url = 'http://wap.cnki.net/touch/web/guide'

7. 既然使用selenium,那么我们需要获取输入框的id来自动输入关键字,输入关键字之后再获取搜索的按钮,然后点击

8.代码如下(输入的关键字是python):

# 请求url
    browser.get(url)
    # 显示等待输入框是否加载完成
    WebDriverWait(browser, 1000).until(
        EC.presence_of_all_elements_located(
            (By.ID, 'keyword')
        )
    )
    # 找到输入框的id并输入python关键字
    browser.find_element_by_id('keyword').send_keys('python')
    # 输入关键字之后点击搜索
    browser.find_element_by_id('btnSearch ').click()

9. 在搜索关键字之后,跳转到这个界面

10.

通过selenium的显示等待,我们可以等待一些这些信息都被加载完成了,之后在进行爬取,这样就可以避免因为元素还没有加载出来而报错,如下图我们可以知道这些信息都是在这个div标签中的,所以我们可以等待这个元素是否加载出来了

# 显示等待文献是否加载完成
        WebDriverWait(browser, 1000).until(
            EC.presence_of_all_elements_located(
                (By.CLASS_NAME, 'g-search-body')
            )
        )

11. 往下面翻页可以看到有个加载更多,通过显示等待判断这个按钮是否加载出来,如果没有加载出来就点击的话,那就报错了

12. 代码,等待这个按钮加载并获取该按钮

# 显示等待加载更多按钮加载完成
            WebDriverWait(browser, 1000).until(
                EC.presence_of_all_elements_located(
                    (By.CLASS_NAME, 'c-company__body-item-more')
                )
            )
            # 获取加载更多按钮
            Btn = browser.find_element_by_class_name('c-company__body-item-more')

13. 基本的讲的差不多了,接下来就是开始获取信息了

14. 获取信息是爬虫的基本能力,这里就不多说了,下图的代码看注释

15. 上面说的意思是这样的,看图,正好我们需要的信息标签都是1,3,5,7,9以此类推,所以是2*count-1

16. 剩下的就没有什么好说的了,代码注释基本都有写,完整代码附上

from selenium import webdriver
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.common.by import By
    from urllib.parse import urljoin
    import time
    import random
    import json
    import csv
# 设置谷歌驱动器的环境
`options = webdriver.ChromeOptions()`
# 设置chrome不加载图片,提高速度
`options.add_experimental_option("prefs", {"profile.managed_default_content_settings.images": 2})`
# 创建一个谷歌驱动器
`browser = webdriver.Chrome(options=options)url = 'http://wap.cnki.net/touch/web/guide'`

# 声明一个全局列表,用来存储字典
`data_list = []`
def start_spider(page):
        # 请求url
        browser.get(url)
        # 显示等待输入框是否加载完成
        WebDriverWait(browser, 1000).until(
            EC.presence_of_all_elements_located(
                (By.ID, 'keyword')
            )
        )
        # 找到输入框的id并输入python关键字
        browser.find_element_by_id('keyword').click()
        browser.find_element_by_id('keyword_ordinary').send_keys('python')
        # 输入关键字之后点击搜索
        browser.find_element_by_class_name('btn-search ').click()
        # print(browser.page_source)
        # 显示等待文献是否加载完成
        WebDriverWait(browser, 1000).until(
            EC.presence_of_all_elements_located(
                (By.CLASS_NAME, 'g-search-body')
            )
        )

        # 声明一个标记用来标记翻页几页
        count = 1
        while True:
            # 显示等待加载更多按钮加载完成
            WebDriverWait(browser, 1000).until(
                EC.presence_of_all_elements_located(
                    (By.CLASS_NAME, 'c-company__body-item-more')
                )
            )
            # 获取加载更多按钮
            Btn = browser.find_element_by_class_name('c-company__body-item-more')
            # 显示等待该信息加载完成
            WebDriverWait(browser, 1000).until(
                EC.presence_of_all_elements_located(
                    (By.XPATH, '//div[@id="searchlist_div"]/div[{}]/div[@class="c-company__body-item"]'.format(2*count-1))
                )
            )
            # 获取在div标签的信息其中format(2*count-1)是因为加载的时候有显示多少条
            # 简单的说就是这些div的信息都是奇数
            divs = browser.find_elements_by_xpath('//div[@id="searchlist_div"]/div[{}]/div[@class="c-company__body-item"]'.format(2*count-1))
            # 遍历循环
            for div in divs:
                # 获取文献的题目
                name = div.find_element_by_class_name('c-company__body-title').text
                # 获取文献的作者
                author = div.find_element_by_class_name('c-company__body-author').text
                # # 获取文献的摘要
                # content = div.find_element_by_class_name('c-company__body-content').text
                # 获取文献的来源和日期文献类型等
                text = div.find_element_by_class_name('c-company__body-name').text.split()
                if (len(text) == 3 and text[-1] == '优先') or len(text) == 2:
                    # 来源
                    source = text[0]
                    # 日期
                    datetime = text[1]
                    # 文献类型
                    literature_type = None
                else:
                    source = text[0]
                    datetime = text[2]
                    literature_type = text[1]
                # 获取下载数和被引数
                temp = div.find_element_by_class_name('c-company__body-info').text.split()
                # 下载数
                download = temp[0].split(':')[-1]
                # 被引数
                cite = temp[1].split(':')[-1]

                # ----------2020-3-18修改----------#
                # 文献链接
                link = div.find_element_by_class_name('c-company-top-link').get_attribute('href')
                # 拼接
                link = urljoin(browser.current_url, link)
                # 获取关键字需要访问该文献url就是上面获取到的link
                # browser.get(link) # 这行和下面那行不推荐使用因为句柄的问题会报错
                # browser.back()
                # 打印查看下未访问新窗口时的句柄
                # print(browser.current_window_handle)
                js = 'window.open("%s");' % link
                # 每次访问链接的时候适当延迟
                time.sleep(random.uniform(1, 2))
                browser.execute_script(js)
                # 打印查看窗口的句柄对比看下当前的句柄是哪个
                # 结果是原先窗口的句柄而不是新打开窗口的句柄因为和上面打印的句柄一样
                # print(browser.current_window_handle)
                # 切换句柄到新打开的窗口browser.window_handles是查看全部的句柄
                # browser.switch_to_window是切换句柄
                browser.switch_to_window(browser.window_handles[1])
                # 获取关键字使用xpath
                key_worlds = browser.find_elements_by_xpath('//div[@class="c-card__paper-name"][contains(text(), "关键词")]/following-sibling::div[1]/a')
                key_worlds = ','.join(map(lambda x: x.text, key_worlds))
                # ----------2020-3-19修改----------#
                # 获取文献的摘要
                content = browser.find_element_by_class_name('c-card__aritcle').text
                # ----------2020-3-19修改----------#
                # 获取信息完之后先关闭当前窗口再切换句柄到原先的窗口
                browser.close()
                browser.switch_to_window(browser.window_handles[0])
                # 切换句柄参考该文章感谢该博主https://blog.csdn.net/DongGeGe214/article/details/52169761
                # ----------2020-3-18修改----------#

                # 声明一个字典存储数据
                data_dict = {}
                data_dict['name'] = name
                data_dict['author'] = author
                data_dict['content'] = content
                data_dict['source'] = source
                data_dict['datetime'] = datetime
                data_dict['literature_type'] = literature_type
                data_dict['download'] = download
                data_dict['cite'] = cite
                data_dict['link'] = link
                data_dict['key_worlds'] = key_worlds

                data_list.append(data_dict)
                print(data_dict)
            # 如果Btn按钮就是加载更多这个按钮没有找到就是已经到底了),就退出
            if not Btn:
                break
            else:
                Btn.click()
            # 如果到了爬取的页数就退出
            if count == page:
                break

            count += 1

            # 延迟两秒我们不是在攻击服务器
            time.sleep(2)
        # 全部爬取结束后退出浏览器
        browser.quit()


    def main():

        start_spider(eval(input('请输入要爬取的页数(如果需要全部爬取请输入0):')))

        # 将数据写入json文件中
        with open('data_json.json', 'a+', encoding='utf-8') as f:
            json.dump(data_list, f, ensure_ascii=False, indent=4)
        print('json文件写入完成')

        # 将数据写入csv文件
        with open('data_csv.csv', 'w', encoding='utf-8', newline='') as f:
            # 表头
            title = data_list[0].keys()
            # 声明writer对象
            writer = csv.DictWriter(f, title)
            # 写入表头
            writer.writeheader()
            # 批量写入数据
            writer.writerows(data_list)
        print('csv文件写入完成')


    if __name__ == '__main__':

        main()


原文链接:https://blog.csdn.net/weixin_44024393/article/details/89221821