阅读 25

爬取需要登录的网站

爬取需要登录信息的网站

不知道算不算违规,不过还是记录一下,属于比较有用的小技巧。有的网站需要登录,才能查看其里面的东西。有时候如果只是文字的东西,想要分享出去。比如说极客时间的专栏。

那就爬取内容保存下来吧。

方法

1 留意自己想要爬的内容,如果可以提前获取其内容链接,并且链接是固定的,那么在前端控制台通过js先获取链接。将程序copy到控制台执行

// 这个links在控制台的时候,为自己获取的htmlelement对象。
var links = [];

var urls = [];

for (var i = 0; i < links.length; i++) {
    var el = links[i];
    var link = el.children[0].getAttribute("href");
    urls.push(link);
}
console.log(urls);
复制代码

2 写Java程序,做好准备工作,先添加依赖

    	<dependency>
            <groupId>io.github.bonigarcia</groupId>
            <artifactId>webdrivermanager</artifactId>
            <version>3.4.0</version>
            <!--<scope>test</scope>-->
        </dependency>

        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>3.141.59</version>
        </dependency>
复制代码

3 规划Java程序,需要有个登录的程序,以及检查是否登录的

    /**
     * 用于在登录之后,通知爬取线程爬取数据
     */
    static Object lock = new Object();
    
    /**
     * 检查浏览器是否登录, 判断是否登录的方式,每个网站都不同,找到判断的方式
     */
    private static class LoginCheckThread extends Thread {
        @Override
        public void run() {
            try {
                Thread.sleep(5 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            while (true) {

                try {
                    Thread.sleep(5 * 1000);

                    List<WebElement> element = driver.findElements(By.className("Om1BnS6m_0"));

                    if (element == null || element.size() == 0) {
                        continue;
                    }
                    String userInfo = element.get(0).getText();
                    if (userInfo.contains("登录")) {
                        System.out.println("用户暂未登录");
                    } else {
                        System.out.println("登录成功");
                        synchronized (lock) {
                            lock.notifyAll();
                        }
                        break;
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }    
复制代码

4 爬取数据的部分

    /**
     * 爬取数据
     * 1 首先等待登录线程
     * 2 关于如何保存,每个人的方式都不同
     * @throws InterruptedException
     * @throws IOException
     */
    private static void extract() throws InterruptedException, IOException {
        synchronized (lock) {
            System.out.println("锁定");
            lock.wait();
            System.out.println("已经解锁");

            for (int i = 0; i < urls.length; i++) {
                driver.get(PREFIX + urls[i]);
                Thread.sleep(5 * 1000);
                System.out.println(driver.getTitle());

                File file = new File("/Users/aihe/Downloads/protocolv2/" + driver.getTitle() + ".jpg");
                BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file));
                bufferedWriter.write(driver.findElement(By.tagName("body")).getText());
                bufferedWriter.close();

                // 如果有需要用于保存快照
//                File screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
//                FileUtils.copyFile(screenshot,file);
            }

        }
    }
复制代码

5 主程序

/**
 * 登录线程与爬取数据线程不在同一个程序之中
 * 最后是否浏览器资源
 * @param args
 */
public static void main(String[] args) {
    WebDriverManager.chromedriver().setup();
    driver = new ChromeDriver();
    try {
        login();
        extract();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        driver.quit();
        System.out.println("end");
    }
}
复制代码

6 效果

image-20190429160403540

最后

这里就是提供一个思路,具体怎么拿数据到时候根据自己的需求来,不过像爬数据是一个很不错的用来练习多线程的方式。

  • 公开的网站,用多线程爬取数据
  • 需要登录的网站,注意控制频率,登录线程与爬取线程的协调

仅做抛转引玉,扩展一下:

  • 有的时候可能爬取下来的内容还是被限制了一次,html中的内容依赖js,如果有文字的话,可以试着使用pandoc转化html文件为其它格式的。
pandoc -s xxx.html -o test.text
复制代码
关注下面的标签,发现更多相似文章
评论