美文网首页Python技巧大全
待在家里出不去?用Python选本书看吧

待在家里出不去?用Python选本书看吧

作者: DigiHacker | 来源:发表于2020-01-26 13:42 被阅读0次

    本文知识点: requests, cookie, BeautifulSoap, redis

    今天天气不错,应该出去走走,我决定去客厅散散心。打开某信出的阅读软件,以前添加的几百本列在那里,感觉都挺好看,可怎么选出最值得看的呢?软件没有书单和排行榜功能,但每本书都有分数和评论人数。一个个点开统计太累人了。这种重复性的工作当然要用编程来解决啊。

    软件提供了Web端,我们只需要拿出requests这个大杀器就可以用普通的get方法就可以了。然而拿到的html提示没登录。为什么呢?因为服务器端认为requests是一个没有登录过的浏览器,所以提示登录。但真要登录的话又需要扫二维码。这就不方便了。

    登录往往是爬虫程序的大敌,一般解决思路是selenium打开浏览器,输入用户名和密码登录后获取cookie. 但往往会遇上验证码,这还要用AI来识别。但我们的情况不需要登录多次,所以只要拿到登录过的cookie就好了。


    1580015148113.png

    用Chrome的同学只要打开开发者工具,选Network,按上头所示就可以拿到cookie, 拷贝后就可以放在程序里了。可是Cookie会过期的,那我们又需要拷贝一次。任何一个有追求的程序员是不会忍受手工操作的。既然Cookie是个文件,那肯定在硬盘上。那我们用Python读取就好了。

    def get_cookie_from_chrome(host):
        cookie_path = os.environ['LOCALAPPDATA'] + r"\Google\Chrome\User Data\Default\Cookies"
        sql = "select host_key,name,encrypted_value from cookies where host_key='%s'" % host
        with sqlite3.connect(cookie_path) as conn:
            cu = conn.cursor()
            cookies = {name: CryptUnprotectData(encrypted_value)[1].decode() for host_key, name, encrypted_value in
                       cu.execute(sql).fetchall()}
            # for host_key, name, encrypted_value in cu.execute(sql).fetchall():
            #     print(f"{host_key}:{name}")
            return cookies
    

    最新版的Chrome是用sqlite管理Cookie的,我们找到Chrome的存放路径后,跑个SQL就可以了。

    有了Cookie,我们就可以去拿任意网页资源了。因为Requests默认的User-Agent可以会被反爬虫程序检测到,所以需要替换为当前浏览器的。同时要注意返回数据可能会出现乱码,需要指定为UTF-8或者GBK等

    def get_page(url):
        global cookie
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36'}
        result = requests.get(url, cookies=cookie, headers=headers)
        result.encoding = 'utf-8'
        return result.text
    

    拿到整个网页后,就需要解析Html来获取我们感兴趣的资源。懂正则的高手这时就可以离开了。但普通程序员还是需要一个html的解析器,比如BeautifulSoup.

       shelfBooks = shelf.find_all(attrs={'class': 'shelfBook'})
            books = []
            for b in shelfBooks:
                try:
                    books.append(Book(root + b.get('href'), b.select('div.title')[0].text))
                except Exception as e:
                    print(f"{b} got {e}")
    

    用find_all通过css class名就可以拿到书架上所有的书,获取它们的详细链接页,然后再用reqeusts获取详细页拿数据。这样的批量操作自然会引起注意。所以每个请求都要sleep下随机时间。

    网络有时不是很稳定,如果没有用多线程的话,一次失败就导致前面的结果丢失了。一方面我们要多用try..except。另一方面我们要随时保存数据。数据库就没什么意思了,来个最近流行的redis吧。 果然非常好用,get和set方法就可以搞定了

    r = redis.Redis(host='192.168.1.250', port=6379, decode_responses=True)
    r.set(book.title, json.dumps(book, cls=UserEncoder))
    
    ...
    saved_book = r.get(book.title)
    
    

    你可以用简单的字符器,也可以用json。

    拿到所有数据后,自然可以按你的需要排序,筛选需要的书了。不知不觉,天怎么黑了

    相关文章

      网友评论

        本文标题:待在家里出不去?用Python选本书看吧

        本文链接:https://www.haomeiwen.com/subject/ruujthtx.html