Tag Archives: coding

How to export Android Chrome tabs to an HTML file in Linux (as of February 2023)

Let’s say you have a few million tabs open in your mobile Chrome browser, because you never close anything, but now your browser is getting slow and laggy. You want to stick the URLs of those tabs somewhere for safekeeping so that you can close them all.

There’s a lot of advice on doing this on the Internet, most of which doesn’t work.

Here’s a method that does work. It’s a bit of a hack, but gives good results:

  • Enable developer tools on your Android phone: go to Settings -> About phone, scroll down to “Build number”, and tap it repeatedly until it tells you you’re a developer. (Seriously.)
  • Enable USB debugging on your phone: go to Settings -> System -> Developer options and make sure the “USB debugging” slider is enabled.
  • Install Android Debug Tools on your Linux desktop: run these commands [h/t this StackOverflow answer]:
    sudo apt install android-tools-adb android-tools-fastboot
    adb device
  • Open USB debugging page in desktop Chrome: go to chrome://inspect/#devices [h/t this Android StackExchange answer
  • Right-click -> Inspect, or press F12
  • Go to the Sources tab. Edit inspect.js (top/inspect/inspect.js) and remove this URL-truncating code [h/t this comment on that answer]:
  if (text.length > 100) {
   text = text.substring(0, 100) + '\u2026';
  • Do not reload! Leave that page open.
  • Tether your phone by USB cable. If a phone pop-up asks you to authorize remote debugging, say yes.
  • You should now see a list of page titles and URLs on the USB debugging page in desktop Chrome.
  • Inspect the page again.
  • Under the Elements tab, navigate to <body>, then <div id="container">, then <div id="content">, then <div id="devices" class="selected">. Right click that last one and Copy -> Copy element.
  • Now you have all your tabs on your clipboard… all on the same line. This will crash a lot of text editors if you try to paste it normally. So we’ll use xclip instead.
  • If you don’t have it, sudo apt install xclip
  • Run xclip -selection c -o > my_tabs_file to put that huge HTML element in a file.
  • This’ll be easier with linebreaks, so run cat my_tabs_file | sed "s/<div/\n<div/g" > my_better_tabs_file
  • Edit the paths at the beginning as appropriate, then run this Python script:
import re

# Put the actual path to the input file here:
INPUT_FILE = '/home/blah/blah/my_better_tabs_file'
# Put the desired path to the output file here:
OUTPUT_FILE = '/home/blah/blah/phone_tabs_list.html'

with open(TABSFILE) as f:
    lines = f.readlines()

prefix = """<!DOCTYPE html>
<html lang="en">
    <meta charset="utf-8">
    <title>My Phone Tabs</title>
outlines = [prefix]

for line in lines:
    name_match = re.match(r'<div class="name">(.*)</div>\n', line)
    url_match = re.match(r'<div class="url">(.*)</div></div>\n', line)
    if name_match:
        name = name_match.group(1)
    elif url_match:
        url = url_match.group(1)
        outlines.append(f'<br/><a href="{url}">{url}</a>\n')
    elif 'class="name"' in line or 'class="url"' in line:
        raise ValueError(f'Could not parse line:\n{line}')

suffix = """  </body>

with open(OUTPUT_FILE, 'w') as f:
  • If you get a ValueError or the file doesn’t look right, please tell me!
  • Open phone_tabs_list.html (or whatever you named it) in your desktop browser of choice. Confirm that it has a bunch of page titles and clickable URLs.
  • Enjoy!

Fun with bitstrings and bijections

Here are two bijections between (infinite) bitstrings and (finite or infinite) sequences of positive integers:

Run-length encoding

You can think of a bitstring as being made up of consecutive runs of one or more 0s or 1s, like “0000” and “111” and “0”.

From bits to integers: Prepend a 0 to the bitstring, then slice it up into runs of 0s and 1s and write down the length of each run. If the string ends in an infinite run, stop the sequence of integers after the last finite run.

From integers to bits: Write down alternating runs of 0s and 1s, with lengths given by the numbers in the sequence. If the sequence stops, write an infinite run of whichever bit value is next. Then delete the first 0.

For example, “001110011100111…” maps to [3, 3, 2, 3, 2, 3…] and “110001100011000…” maps to [1, 2, 3, 2, 3, 2, 3…].

The annoying extra-0 trick is to distinguish pairs of bitstrings like the above, which are flipped versions of each other.

Note that “00000…” maps to [] and “11111…” maps to [1].

Gaps between 1s

On the other hand, you can think of a bitstring as being made up of runs of zero or more 0s ending in a single 1, like “001” and “000001” and “1”.

From bits to integers: For each 1 in the bitstring, write down the number of 0s immediately preceding it plus one. If the bitstring ends in an infinite run of zeros, stop the sequence of integers after the last 1.

From integers to bits: For each number N in the sequence, write down N-1 0s and then one 1. If the sequence stops, write an infinite run of 0s.

Note that “00000…” maps to [] and “11111…” maps to [1, 1, 1, 1, 1…]

Both at once?

The all-zeros string maps to an empty list under both bijections, but the all-ones string is different. It’s also easy to see that these bijections are pretty different on a generic bitstring.

Suppose we start with the list [1] and repeatedly do the following:

  • Encode the list into a bitstring using the run-length-encoding map
  • Decode that bitstring into a list using the gaps-between-1s map

What does the sequence of bitstrings look like?

The first few steps look like this:

[1] –> 11111…

11111… –> [1, 1, 1, 1, 1…]

[1, 1, 1, 1, 1…] –> 101010…

101010… –> [1, 2, 2, 2…]

[1, 2, 2, 2…] –> 110011…

So our first few bitstrings are:


I’ll let you discover the pattern for yourself (pen and paper is sufficient, but Python is faster), but if you get impatient CLICK HERE to see the first 64 bits of each of the first 64 strings.